diff options
Diffstat (limited to 'indra/llaudio')
22 files changed, 3212 insertions, 4847 deletions
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 4f469b9bb5..9278d3c488 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,7 +4,6 @@ project(llaudio) include(00-Common) include(LLAudio) -include(FMODSTUDIO) include(OPENAL) include(LLCommon) @@ -25,20 +24,6 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (TARGET ll::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 () - if (TARGET ll::openal) list(APPEND llaudio_SOURCE_FILES llaudioengine_openal.cpp diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 190c5290cb..d8a6fffea6 100755 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llaudiodecodemgr.cpp * * $LicenseInfo:firstyear=2003&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$ */ @@ -56,476 +56,476 @@ static const S32 WAV_HEADER_SIZE = 44; class LLVorbisDecodeState : public LLThreadSafeRefCount { public: - class WriteResponder : public LLLFSThread::Responder - { - public: - WriteResponder(LLVorbisDecodeState* decoder) : mDecoder(decoder) {} - ~WriteResponder() {} - void completed(S32 bytes) - { - mDecoder->ioComplete(bytes); - } - LLPointer<LLVorbisDecodeState> mDecoder; - }; - - LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename); - - BOOL initDecode(); - BOOL decodeSection(); // Return TRUE if done. - BOOL finishDecode(); - - void flushBadFile(); - - void ioComplete(S32 bytes) { mBytesRead = bytes; } - BOOL isValid() const { return mValid; } - BOOL isDone() const { return mDone; } - const LLUUID &getUUID() const { return mUUID; } + class WriteResponder : public LLLFSThread::Responder + { + public: + WriteResponder(LLVorbisDecodeState* decoder) : mDecoder(decoder) {} + ~WriteResponder() {} + void completed(S32 bytes) + { + mDecoder->ioComplete(bytes); + } + LLPointer<LLVorbisDecodeState> mDecoder; + }; + + LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename); + + bool initDecode(); + bool decodeSection(); // Return true if done. + bool finishDecode(); + + void flushBadFile(); + + void ioComplete(S32 bytes) { mBytesRead = bytes; } + bool isValid() const { return mValid; } + bool isDone() const { return mDone; } + const LLUUID &getUUID() const { return mUUID; } protected: - virtual ~LLVorbisDecodeState(); - - BOOL mValid; - BOOL mDone; - LLAtomicS32 mBytesRead; - LLUUID mUUID; - - std::vector<U8> mWAVBuffer; - std::string mOutFilename; - LLLFSThread::handle_t mFileHandle; - - LLFileSystem *mInFilep; - OggVorbis_File mVF; - S32 mCurrentSection; + virtual ~LLVorbisDecodeState(); + + bool mValid; + bool mDone; + LLAtomicS32 mBytesRead; + LLUUID mUUID; + + std::vector<U8> mWAVBuffer; + std::string mOutFilename; + LLLFSThread::handle_t mFileHandle; + + LLFileSystem *mInFilep; + OggVorbis_File mVF; + S32 mCurrentSection; }; size_t cache_read(void *ptr, size_t size, size_t nmemb, void *datasource) { - LLFileSystem *file = (LLFileSystem *)datasource; - - if (file->read((U8*)ptr, (S32)(size * nmemb))) /*Flawfinder: ignore*/ - { - S32 read = file->getLastBytesRead(); - return read / size; /*Flawfinder: ignore*/ - } - else - { - return 0; - } + LLFileSystem *file = (LLFileSystem *)datasource; + + if (file->read((U8*)ptr, (S32)(size * nmemb))) /*Flawfinder: ignore*/ + { + S32 read = file->getLastBytesRead(); + return read / size; /*Flawfinder: ignore*/ + } + else + { + return 0; + } } S32 cache_seek(void *datasource, ogg_int64_t offset, S32 whence) { - LLFileSystem *file = (LLFileSystem *)datasource; - - // cache has 31-bit files - if (offset > S32_MAX) - { - return -1; - } - - S32 origin; - switch (whence) { - case SEEK_SET: - origin = 0; - break; - case SEEK_END: - origin = file->getSize(); - break; - case SEEK_CUR: - origin = -1; - break; - default: - LL_ERRS("AudioEngine") << "Invalid whence argument to cache_seek" << LL_ENDL; - return -1; - } - - if (file->seek((S32)offset, origin)) - { - return 0; - } - else - { - return -1; - } + LLFileSystem *file = (LLFileSystem *)datasource; + + // cache has 31-bit files + if (offset > S32_MAX) + { + return -1; + } + + S32 origin; + switch (whence) { + case SEEK_SET: + origin = 0; + break; + case SEEK_END: + origin = file->getSize(); + break; + case SEEK_CUR: + origin = -1; + break; + default: + LL_ERRS("AudioEngine") << "Invalid whence argument to cache_seek" << LL_ENDL; + return -1; + } + + if (file->seek((S32)offset, origin)) + { + return 0; + } + else + { + return -1; + } } S32 cache_close (void *datasource) { - LLFileSystem *file = (LLFileSystem *)datasource; - delete file; - return 0; + LLFileSystem *file = (LLFileSystem *)datasource; + delete file; + return 0; } long cache_tell (void *datasource) { - LLFileSystem *file = (LLFileSystem *)datasource; - return file->tell(); + LLFileSystem *file = (LLFileSystem *)datasource; + return file->tell(); } LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string &out_filename) { - mDone = FALSE; - mValid = FALSE; - mBytesRead = -1; - mUUID = uuid; - mInFilep = NULL; - mCurrentSection = 0; - mOutFilename = out_filename; - mFileHandle = LLLFSThread::nullHandle(); + mDone = false; + mValid = false; + mBytesRead = -1; + mUUID = uuid; + mInFilep = NULL; + mCurrentSection = 0; + mOutFilename = out_filename; + mFileHandle = LLLFSThread::nullHandle(); // No default value for mVF, it's an ogg structure? - // Hey, let's zero it anyway, for predictability. - memset(&mVF, 0, sizeof(mVF)); + // Hey, let's zero it anyway, for predictability. + memset(&mVF, 0, sizeof(mVF)); } LLVorbisDecodeState::~LLVorbisDecodeState() { - if (!mDone) - { - delete mInFilep; - mInFilep = NULL; - } + if (!mDone) + { + delete mInFilep; + mInFilep = NULL; + } } -BOOL LLVorbisDecodeState::initDecode() +bool LLVorbisDecodeState::initDecode() { - ov_callbacks cache_callbacks; - cache_callbacks.read_func = cache_read; - cache_callbacks.seek_func = cache_seek; - cache_callbacks.close_func = cache_close; - cache_callbacks.tell_func = cache_tell; - - LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL; - - mInFilep = new LLFileSystem(mUUID, LLAssetType::AT_SOUND); - if (!mInFilep || !mInFilep->getSize()) - { - LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; - delete mInFilep; - mInFilep = NULL; - return FALSE; - } - - S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, cache_callbacks); - if(r < 0) - { - LL_WARNS("AudioEngine") << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL; - return(FALSE); - } - - S32 sample_count = (S32)ov_pcm_total(&mVF, -1); - size_t size_guess = (size_t)sample_count; - vorbis_info* vi = ov_info(&mVF, -1); - size_guess *= (vi? vi->channels : 1); - size_guess *= 2; - size_guess += 2048; - - bool abort_decode = false; - - if (vi) - { - if( vi->channels < 1 || vi->channels > LLVORBIS_CLIP_MAX_CHANNELS ) - { - abort_decode = true; - LL_WARNS("AudioEngine") << "Bad channel count: " << vi->channels << LL_ENDL; - } - } - else // !vi - { - abort_decode = true; - LL_WARNS("AudioEngine") << "No default bitstream found" << LL_ENDL; - } - - if( (size_t)sample_count > LLVORBIS_CLIP_REJECT_SAMPLES || - (size_t)sample_count <= 0) - { - abort_decode = true; - LL_WARNS("AudioEngine") << "Illegal sample count: " << sample_count << LL_ENDL; - } - - if( size_guess > LLVORBIS_CLIP_REJECT_SIZE ) - { - abort_decode = true; - LL_WARNS("AudioEngine") << "Illegal sample size: " << size_guess << LL_ENDL; - } - - if( abort_decode ) - { - LL_WARNS("AudioEngine") << "Canceling initDecode. Bad asset: " << mUUID << LL_ENDL; - vorbis_comment* comment = ov_comment(&mVF,-1); - if (comment && comment->vendor) - { - LL_WARNS("AudioEngine") << "Bad asset encoded by: " << comment->vendor << LL_ENDL; - } - delete mInFilep; - mInFilep = NULL; - return FALSE; - } - - try - { - mWAVBuffer.reserve(size_guess); - mWAVBuffer.resize(WAV_HEADER_SIZE); - } - catch (std::bad_alloc&) - { - LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL; - delete mInFilep; - mInFilep = NULL; - return FALSE; - } - - { - // write the .wav format header - //"RIFF" - mWAVBuffer[0] = 0x52; - mWAVBuffer[1] = 0x49; - mWAVBuffer[2] = 0x46; - mWAVBuffer[3] = 0x46; - - // length = datalen + 36 (to be filled in later) - mWAVBuffer[4] = 0x00; - mWAVBuffer[5] = 0x00; - mWAVBuffer[6] = 0x00; - mWAVBuffer[7] = 0x00; - - //"WAVE" - mWAVBuffer[8] = 0x57; - mWAVBuffer[9] = 0x41; - mWAVBuffer[10] = 0x56; - mWAVBuffer[11] = 0x45; - - // "fmt " - mWAVBuffer[12] = 0x66; - mWAVBuffer[13] = 0x6D; - mWAVBuffer[14] = 0x74; - mWAVBuffer[15] = 0x20; - - // chunk size = 16 - mWAVBuffer[16] = 0x10; - mWAVBuffer[17] = 0x00; - mWAVBuffer[18] = 0x00; - mWAVBuffer[19] = 0x00; - - // format (1 = PCM) - mWAVBuffer[20] = 0x01; - mWAVBuffer[21] = 0x00; - - // number of channels - mWAVBuffer[22] = 0x01; - mWAVBuffer[23] = 0x00; - - // samples per second - mWAVBuffer[24] = 0x44; - mWAVBuffer[25] = 0xAC; - mWAVBuffer[26] = 0x00; - mWAVBuffer[27] = 0x00; - - // average bytes per second - mWAVBuffer[28] = 0x88; - mWAVBuffer[29] = 0x58; - mWAVBuffer[30] = 0x01; - mWAVBuffer[31] = 0x00; - - // bytes to output at a single time - mWAVBuffer[32] = 0x02; - mWAVBuffer[33] = 0x00; - - // 16 bits per sample - mWAVBuffer[34] = 0x10; - mWAVBuffer[35] = 0x00; - - // "data" - mWAVBuffer[36] = 0x64; - mWAVBuffer[37] = 0x61; - mWAVBuffer[38] = 0x74; - mWAVBuffer[39] = 0x61; - - // these are the length of the data chunk, to be filled in later - mWAVBuffer[40] = 0x00; - mWAVBuffer[41] = 0x00; - mWAVBuffer[42] = 0x00; - mWAVBuffer[43] = 0x00; - } - - //{ - //char **ptr=ov_comment(&mVF,-1)->user_comments; -// vorbis_info *vi=ov_info(&vf,-1); - //while(*ptr){ - // fprintf(stderr,"%s\n",*ptr); - // ++ptr; - //} + ov_callbacks cache_callbacks; + cache_callbacks.read_func = cache_read; + cache_callbacks.seek_func = cache_seek; + cache_callbacks.close_func = cache_close; + cache_callbacks.tell_func = cache_tell; + + LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL; + + mInFilep = new LLFileSystem(mUUID, LLAssetType::AT_SOUND); + if (!mInFilep || !mInFilep->getSize()) + { + LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; + delete mInFilep; + mInFilep = NULL; + return false; + } + + S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, cache_callbacks); + if(r < 0) + { + LL_WARNS("AudioEngine") << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL; + return(false); + } + + S32 sample_count = (S32)ov_pcm_total(&mVF, -1); + size_t size_guess = (size_t)sample_count; + vorbis_info* vi = ov_info(&mVF, -1); + size_guess *= (vi? vi->channels : 1); + size_guess *= 2; + size_guess += 2048; + + bool abort_decode = false; + + if (vi) + { + if( vi->channels < 1 || vi->channels > LLVORBIS_CLIP_MAX_CHANNELS ) + { + abort_decode = true; + LL_WARNS("AudioEngine") << "Bad channel count: " << vi->channels << LL_ENDL; + } + } + else // !vi + { + abort_decode = true; + LL_WARNS("AudioEngine") << "No default bitstream found" << LL_ENDL; + } + + if( (size_t)sample_count > LLVORBIS_CLIP_REJECT_SAMPLES || + (size_t)sample_count <= 0) + { + abort_decode = true; + LL_WARNS("AudioEngine") << "Illegal sample count: " << sample_count << LL_ENDL; + } + + if( size_guess > LLVORBIS_CLIP_REJECT_SIZE ) + { + abort_decode = true; + LL_WARNS("AudioEngine") << "Illegal sample size: " << size_guess << LL_ENDL; + } + + if( abort_decode ) + { + LL_WARNS("AudioEngine") << "Canceling initDecode. Bad asset: " << mUUID << LL_ENDL; + vorbis_comment* comment = ov_comment(&mVF,-1); + if (comment && comment->vendor) + { + LL_WARNS("AudioEngine") << "Bad asset encoded by: " << comment->vendor << LL_ENDL; + } + delete mInFilep; + mInFilep = NULL; + return false; + } + + try + { + mWAVBuffer.reserve(size_guess); + mWAVBuffer.resize(WAV_HEADER_SIZE); + } + catch (std::bad_alloc&) + { + LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL; + delete mInFilep; + mInFilep = NULL; + return false; + } + + { + // write the .wav format header + //"RIFF" + mWAVBuffer[0] = 0x52; + mWAVBuffer[1] = 0x49; + mWAVBuffer[2] = 0x46; + mWAVBuffer[3] = 0x46; + + // length = datalen + 36 (to be filled in later) + mWAVBuffer[4] = 0x00; + mWAVBuffer[5] = 0x00; + mWAVBuffer[6] = 0x00; + mWAVBuffer[7] = 0x00; + + //"WAVE" + mWAVBuffer[8] = 0x57; + mWAVBuffer[9] = 0x41; + mWAVBuffer[10] = 0x56; + mWAVBuffer[11] = 0x45; + + // "fmt " + mWAVBuffer[12] = 0x66; + mWAVBuffer[13] = 0x6D; + mWAVBuffer[14] = 0x74; + mWAVBuffer[15] = 0x20; + + // chunk size = 16 + mWAVBuffer[16] = 0x10; + mWAVBuffer[17] = 0x00; + mWAVBuffer[18] = 0x00; + mWAVBuffer[19] = 0x00; + + // format (1 = PCM) + mWAVBuffer[20] = 0x01; + mWAVBuffer[21] = 0x00; + + // number of channels + mWAVBuffer[22] = 0x01; + mWAVBuffer[23] = 0x00; + + // samples per second + mWAVBuffer[24] = 0x44; + mWAVBuffer[25] = 0xAC; + mWAVBuffer[26] = 0x00; + mWAVBuffer[27] = 0x00; + + // average bytes per second + mWAVBuffer[28] = 0x88; + mWAVBuffer[29] = 0x58; + mWAVBuffer[30] = 0x01; + mWAVBuffer[31] = 0x00; + + // bytes to output at a single time + mWAVBuffer[32] = 0x02; + mWAVBuffer[33] = 0x00; + + // 16 bits per sample + mWAVBuffer[34] = 0x10; + mWAVBuffer[35] = 0x00; + + // "data" + mWAVBuffer[36] = 0x64; + mWAVBuffer[37] = 0x61; + mWAVBuffer[38] = 0x74; + mWAVBuffer[39] = 0x61; + + // these are the length of the data chunk, to be filled in later + mWAVBuffer[40] = 0x00; + mWAVBuffer[41] = 0x00; + mWAVBuffer[42] = 0x00; + mWAVBuffer[43] = 0x00; + } + + //{ + //char **ptr=ov_comment(&mVF,-1)->user_comments; +// vorbis_info *vi=ov_info(&vf,-1); + //while(*ptr){ + // fprintf(stderr,"%s\n",*ptr); + // ++ptr; + //} // fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate); // fprintf(stderr,"\nDecoded length: %ld samples\n", (long)ov_pcm_total(&vf,-1)); // fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor); - //} - return TRUE; + //} + return true; } -BOOL LLVorbisDecodeState::decodeSection() +bool LLVorbisDecodeState::decodeSection() { - if (!mInFilep) - { - LL_WARNS("AudioEngine") << "No cache file to decode in vorbis!" << LL_ENDL; - return TRUE; - } - if (mDone) - { -// LL_WARNS("AudioEngine") << "Already done with decode, aborting!" << LL_ENDL; - return TRUE; - } - char pcmout[4096]; /*Flawfinder: ignore*/ - - BOOL eof = FALSE; - long ret=ov_read(&mVF, pcmout, sizeof(pcmout), 0, 2, 1, &mCurrentSection); - if (ret == 0) - { - /* EOF */ - eof = TRUE; - mDone = TRUE; - mValid = TRUE; -// LL_INFOS("AudioEngine") << "Vorbis EOF" << LL_ENDL; - } - else if (ret < 0) - { - /* error in the stream. Not a problem, just reporting it in - case we (the app) cares. In this case, we don't. */ - - LL_WARNS("AudioEngine") << "BAD vorbis decode in decodeSection." << LL_ENDL; - - mValid = FALSE; - mDone = TRUE; - // We're done, return TRUE. - return TRUE; - } - else - { -// LL_INFOS("AudioEngine") << "Vorbis read " << ret << "bytes" << LL_ENDL; - /* we don't bother dealing with sample rate changes, etc, but. - you'll have to*/ - std::copy(pcmout, pcmout+ret, std::back_inserter(mWAVBuffer)); - } - return eof; + if (!mInFilep) + { + LL_WARNS("AudioEngine") << "No cache file to decode in vorbis!" << LL_ENDL; + return true; + } + if (mDone) + { +// LL_WARNS("AudioEngine") << "Already done with decode, aborting!" << LL_ENDL; + return true; + } + char pcmout[4096]; /*Flawfinder: ignore*/ + + bool eof = false; + long ret=ov_read(&mVF, pcmout, sizeof(pcmout), 0, 2, 1, &mCurrentSection); + if (ret == 0) + { + /* EOF */ + eof = true; + mDone = true; + mValid = true; +// LL_INFOS("AudioEngine") << "Vorbis EOF" << LL_ENDL; + } + else if (ret < 0) + { + /* error in the stream. Not a problem, just reporting it in + case we (the app) cares. In this case, we don't. */ + + LL_WARNS("AudioEngine") << "BAD vorbis decode in decodeSection." << LL_ENDL; + + mValid = false; + mDone = true; + // We're done, return true. + return true; + } + else + { +// LL_INFOS("AudioEngine") << "Vorbis read " << ret << "bytes" << LL_ENDL; + /* we don't bother dealing with sample rate changes, etc, but. + you'll have to*/ + std::copy(pcmout, pcmout+ret, std::back_inserter(mWAVBuffer)); + } + return eof; } -BOOL LLVorbisDecodeState::finishDecode() +bool LLVorbisDecodeState::finishDecode() { - if (!isValid()) - { - LL_WARNS("AudioEngine") << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << LL_ENDL; - return TRUE; // We've finished - } - - if (mFileHandle == LLLFSThread::nullHandle()) - { - ov_clear(&mVF); - - // write "data" chunk length, in little-endian format - S32 data_length = mWAVBuffer.size() - WAV_HEADER_SIZE; - mWAVBuffer[40] = (data_length) & 0x000000FF; - mWAVBuffer[41] = (data_length >> 8) & 0x000000FF; - mWAVBuffer[42] = (data_length >> 16) & 0x000000FF; - mWAVBuffer[43] = (data_length >> 24) & 0x000000FF; - // write overall "RIFF" length, in little-endian format - data_length += 36; - mWAVBuffer[4] = (data_length) & 0x000000FF; - mWAVBuffer[5] = (data_length >> 8) & 0x000000FF; - mWAVBuffer[6] = (data_length >> 16) & 0x000000FF; - mWAVBuffer[7] = (data_length >> 24) & 0x000000FF; - - // - // FUDGECAKES!!! Vorbis encode/decode messes up loop point transitions (pop) - // do a cheap-and-cheesy crossfade - // - { - S16 *samplep; - S32 i; - S32 fade_length; - char pcmout[4096]; /*Flawfinder: ignore*/ - - fade_length = llmin((S32)128,(S32)(data_length-36)/8); - if((S32)mWAVBuffer.size() >= (WAV_HEADER_SIZE + 2* fade_length)) - { - memcpy(pcmout, &mWAVBuffer[WAV_HEADER_SIZE], (2 * fade_length)); /*Flawfinder: ignore*/ - } - llendianswizzle(&pcmout, 2, fade_length); - - samplep = (S16 *)pcmout; - for (i = 0 ;i < fade_length; i++) - { - *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); - samplep++; - } - - llendianswizzle(&pcmout, 2, fade_length); - if((WAV_HEADER_SIZE+(2 * fade_length)) < (S32)mWAVBuffer.size()) - { - memcpy(&mWAVBuffer[WAV_HEADER_SIZE], pcmout, (2 * fade_length)); /*Flawfinder: ignore*/ - } - S32 near_end = mWAVBuffer.size() - (2 * fade_length); - if ((S32)mWAVBuffer.size() >= ( near_end + 2* fade_length)) - { - memcpy(pcmout, &mWAVBuffer[near_end], (2 * fade_length)); /*Flawfinder: ignore*/ - } - llendianswizzle(&pcmout, 2, fade_length); - - samplep = (S16 *)pcmout; - for (i = fade_length-1 ; i >= 0; i--) - { - *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); - samplep++; - } - - llendianswizzle(&pcmout, 2, fade_length); - if (near_end + (2 * fade_length) < (S32)mWAVBuffer.size()) - { - memcpy(&mWAVBuffer[near_end], pcmout, (2 * fade_length));/*Flawfinder: ignore*/ - } - } - - if (36 == data_length) - { - LL_WARNS("AudioEngine") << "BAD Vorbis decode in finishDecode!" << LL_ENDL; - mValid = FALSE; - return TRUE; // we've finished - } - mBytesRead = -1; - mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, mWAVBuffer.size(), - new WriteResponder(this)); - } - - if (mFileHandle != LLLFSThread::nullHandle()) - { - if (mBytesRead >= 0) - { - if (mBytesRead == 0) - { - LL_WARNS("AudioEngine") << "Unable to write file in LLVorbisDecodeState::finishDecode" << LL_ENDL; - mValid = FALSE; - return TRUE; // we've finished - } - } - else - { - return FALSE; // not done - } - } - - mDone = TRUE; - - LL_DEBUGS("AudioEngine") << "Finished decode for " << getUUID() << LL_ENDL; - - return TRUE; + if (!isValid()) + { + LL_WARNS("AudioEngine") << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << LL_ENDL; + return true; // We've finished + } + + if (mFileHandle == LLLFSThread::nullHandle()) + { + ov_clear(&mVF); + + // write "data" chunk length, in little-endian format + S32 data_length = static_cast<S32>(mWAVBuffer.size()) - WAV_HEADER_SIZE; + mWAVBuffer[40] = (data_length) & 0x000000FF; + mWAVBuffer[41] = (data_length >> 8) & 0x000000FF; + mWAVBuffer[42] = (data_length >> 16) & 0x000000FF; + mWAVBuffer[43] = (data_length >> 24) & 0x000000FF; + // write overall "RIFF" length, in little-endian format + data_length += 36; + mWAVBuffer[4] = (data_length) & 0x000000FF; + mWAVBuffer[5] = (data_length >> 8) & 0x000000FF; + mWAVBuffer[6] = (data_length >> 16) & 0x000000FF; + mWAVBuffer[7] = (data_length >> 24) & 0x000000FF; + + // + // FUDGECAKES!!! Vorbis encode/decode messes up loop point transitions (pop) + // do a cheap-and-cheesy crossfade + // + { + S16 *samplep; + S32 i; + S32 fade_length; + char pcmout[4096]; /*Flawfinder: ignore*/ + + fade_length = llmin((S32)128,(S32)(data_length-36)/8); + if((S32)mWAVBuffer.size() >= (WAV_HEADER_SIZE + 2* fade_length)) + { + memcpy(pcmout, &mWAVBuffer[WAV_HEADER_SIZE], (2 * fade_length)); /*Flawfinder: ignore*/ + } + llendianswizzle(&pcmout, 2, fade_length); + + samplep = (S16 *)pcmout; + for (i = 0 ;i < fade_length; i++) + { + *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); + samplep++; + } + + llendianswizzle(&pcmout, 2, fade_length); + if((WAV_HEADER_SIZE+(2 * fade_length)) < (S32)mWAVBuffer.size()) + { + memcpy(&mWAVBuffer[WAV_HEADER_SIZE], pcmout, (2 * fade_length)); /*Flawfinder: ignore*/ + } + S32 near_end = static_cast<S32>(mWAVBuffer.size()) - (2 * fade_length); + if ((S32)mWAVBuffer.size() >= ( near_end + 2* fade_length)) + { + memcpy(pcmout, &mWAVBuffer[near_end], (2 * fade_length)); /*Flawfinder: ignore*/ + } + llendianswizzle(&pcmout, 2, fade_length); + + samplep = (S16 *)pcmout; + for (i = fade_length-1 ; i >= 0; i--) + { + *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); + samplep++; + } + + llendianswizzle(&pcmout, 2, fade_length); + if (near_end + (2 * fade_length) < (S32)mWAVBuffer.size()) + { + memcpy(&mWAVBuffer[near_end], pcmout, (2 * fade_length));/*Flawfinder: ignore*/ + } + } + + if (36 == data_length) + { + LL_WARNS("AudioEngine") << "BAD Vorbis decode in finishDecode!" << LL_ENDL; + mValid = false; + return true; // we've finished + } + mBytesRead = -1; + mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, static_cast<S32>(mWAVBuffer.size()), + new WriteResponder(this)); + } + + if (mFileHandle != LLLFSThread::nullHandle()) + { + if (mBytesRead >= 0) + { + if (mBytesRead == 0) + { + LL_WARNS("AudioEngine") << "Unable to write file in LLVorbisDecodeState::finishDecode" << LL_ENDL; + mValid = false; + return true; // we've finished + } + } + else + { + return false; // not done + } + } + + mDone = true; + + LL_DEBUGS("AudioEngine") << "Finished decode for " << getUUID() << LL_ENDL; + + return true; } void LLVorbisDecodeState::flushBadFile() { - if (mInFilep) - { - LL_WARNS("AudioEngine") << "Flushing bad vorbis file from cache for " << mUUID << LL_ENDL; - mInFilep->remove(); - } + if (mInFilep) + { + LL_WARNS("AudioEngine") << "Flushing bad vorbis file from cache for " << mUUID << LL_ENDL; + mInFilep->remove(); + } } ////////////////////////////////////////////////////////////////////////////// @@ -779,23 +779,26 @@ void LLAudioDecodeMgr::processQueue() mImpl->processQueue(); } -BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) +bool LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) { - if (gAudiop && gAudiop->hasDecodedFile(uuid)) - { - // Already have a decoded version, don't need to decode it. - LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has decoded file already" << LL_ENDL; - return TRUE; - } - - if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) - { - // Just put it on the decode queue. - LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL; - mImpl->mDecodeQueue.push_back(uuid); - return TRUE; - } - - LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " no file available" << LL_ENDL; - return FALSE; + if (gAudiop && gAudiop->hasDecodedFile(uuid)) + { + // Already have a decoded version, don't need to decode it. + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has decoded file already" << LL_ENDL; + return true; + } + + if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + { + // Just put it on the decode queue it if it's not already in the queue + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL; + if (std::find(mImpl->mDecodeQueue.begin(), mImpl->mDecodeQueue.end(), uuid) == mImpl->mDecodeQueue.end()) + { + mImpl->mDecodeQueue.emplace_back(uuid); + } + return true; + } + + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " no file available" << LL_ENDL; + return false; } diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h index 4c17b46156..79f8b8e92e 100644 --- a/indra/llaudio/llaudiodecodemgr.h +++ b/indra/llaudio/llaudiodecodemgr.h @@ -1,24 +1,24 @@ -/** +/** * @file llaudiodecodemgr.h * * $LicenseInfo:firstyear=2003&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$ */ @@ -42,12 +42,12 @@ class LLAudioDecodeMgr : public LLSingleton<LLAudioDecodeMgr> LLSINGLETON(LLAudioDecodeMgr); ~LLAudioDecodeMgr(); public: - void processQueue(); - BOOL addDecodeRequest(const LLUUID &uuid); - void addAudioRequest(const LLUUID &uuid); - + void processQueue(); + bool addDecodeRequest(const LLUUID &uuid); + void addAudioRequest(const LLUUID &uuid); + protected: - class Impl; + class Impl; Impl* mImpl; }; diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index ece0a12a7a..613c408157 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -1,4 +1,4 @@ - /** + /** * @file audioengine.cpp * @brief implementation of LLAudioEngine class abstracting the Open * AL audio support @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2000&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$ */ @@ -41,7 +41,7 @@ #include "llassetstorage.h" -// necessary for grabbing sounds from sim (implemented in viewer) +// necessary for grabbing sounds from sim (implemented in viewer) extern void request_sound(const LLUUID &sound_guid); LLAudioEngine* gAudiop = NULL; @@ -54,7 +54,7 @@ LLAudioEngine* gAudiop = NULL; LLAudioEngine::LLAudioEngine() { - setDefaults(); + setDefaults(); } @@ -64,1173 +64,1173 @@ LLAudioEngine::~LLAudioEngine() LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl() { - return mStreamingAudioImpl; + return mStreamingAudioImpl; } void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl) { - mStreamingAudioImpl = impl; + mStreamingAudioImpl = impl; } void LLAudioEngine::setDefaults() { - mMaxWindGain = 1.f; + mMaxWindGain = 1.f; - mListenerp = NULL; + mListenerp = NULL; - mMuted = false; - mUserData = NULL; + mMuted = false; + mUserData = NULL; - mLastStatus = 0; + mLastStatus = 0; - mEnableWind = false; + mEnableWind = false; - mChannels.fill(nullptr); - mBuffers.fill(nullptr); + mChannels.fill(nullptr); + mBuffers.fill(nullptr); - mMasterGain = 1.f; - // Setting mInternalGain to an out of range value fixes the issue reported in STORM-830. - // There is an edge case in setMasterGain during startup which prevents setInternalGain from - // being called if the master volume setting and mInternalGain both equal 0, so using -1 forces - // the if statement in setMasterGain to execute when the viewer starts up. - mInternalGain = -1.f; - mNextWindUpdate = 0.f; + mMasterGain = 1.f; + // Setting mInternalGain to an out of range value fixes the issue reported in STORM-830. + // There is an edge case in setMasterGain during startup which prevents setInternalGain from + // being called if the master volume setting and mInternalGain both equal 0, so using -1 forces + // the if statement in setMasterGain to execute when the viewer starts up. + mInternalGain = -1.f; + mNextWindUpdate = 0.f; - mStreamingAudioImpl = NULL; + mStreamingAudioImpl = NULL; - for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++) - mSecondaryGain[i] = 1.0f; + for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++) + mSecondaryGain[i] = 1.0f; } bool LLAudioEngine::init(void* userdata, const std::string &app_title) { - setDefaults(); + setDefaults(); - mUserData = userdata; - - allocateListener(); + mUserData = userdata; - LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << LL_ENDL; + allocateListener(); - return true; + LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << LL_ENDL; + + return true; } void LLAudioEngine::shutdown() { - // Clean up wind source - cleanupWind(); + // Clean up wind source + cleanupWind(); - // Clean up audio sources - for (source_map::value_type& src_pair : mAllSources) - { - delete src_pair.second; - } + // Clean up audio sources + for (source_map::value_type& src_pair : mAllSources) + { + delete src_pair.second; + } - // Clean up audio data - for (data_map::value_type& data_pair : mAllData) - { - delete data_pair.second; - } + // Clean up audio data + for (data_map::value_type& data_pair : mAllData) + { + delete data_pair.second; + } - // Clean up channels - S32 i; - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - delete mChannels[i]; - mChannels[i] = NULL; - } + // Clean up channels + S32 i; + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + delete mChannels[i]; + mChannels[i] = NULL; + } - // Clean up buffers - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - delete mBuffers[i]; - mBuffers[i] = NULL; - } + // Clean up buffers + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + delete mBuffers[i]; + mBuffers[i] = NULL; + } } // virtual void LLAudioEngine::startInternetStream(const std::string& url) { - if (mStreamingAudioImpl) - mStreamingAudioImpl->start(url); + if (mStreamingAudioImpl) + mStreamingAudioImpl->start(url); } // virtual void LLAudioEngine::stopInternetStream() { - if (mStreamingAudioImpl) - mStreamingAudioImpl->stop(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->stop(); } // virtual void LLAudioEngine::pauseInternetStream(S32 pause) { - if (mStreamingAudioImpl) - mStreamingAudioImpl->pause(pause); + if (mStreamingAudioImpl) + mStreamingAudioImpl->pause(pause); } // virtual void LLAudioEngine::updateInternetStream() { - if (mStreamingAudioImpl) - mStreamingAudioImpl->update(); + if (mStreamingAudioImpl) + mStreamingAudioImpl->update(); } // virtual LLAudioEngine::LLAudioPlayState LLAudioEngine::isInternetStreamPlaying() { - if (mStreamingAudioImpl) - return (LLAudioEngine::LLAudioPlayState) mStreamingAudioImpl->isPlaying(); + if (mStreamingAudioImpl) + return (LLAudioEngine::LLAudioPlayState) mStreamingAudioImpl->isPlaying(); - return LLAudioEngine::AUDIO_STOPPED; // Stopped + return LLAudioEngine::AUDIO_STOPPED; // Stopped } // virtual void LLAudioEngine::setInternetStreamGain(F32 vol) { - if (mStreamingAudioImpl) - mStreamingAudioImpl->setGain(vol); + if (mStreamingAudioImpl) + mStreamingAudioImpl->setGain(vol); } // virtual std::string LLAudioEngine::getInternetStreamURL() { - if (mStreamingAudioImpl) - return mStreamingAudioImpl->getURL(); + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getURL(); - return std::string(); + return std::string(); } void LLAudioEngine::updateChannels() { - S32 i; - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (mChannels[i]) - { - mChannels[i]->updateBuffer(); - mChannels[i]->update3DPosition(); - mChannels[i]->updateLoop(); - } - } + S32 i; + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + if (mChannels[i]) + { + mChannels[i]->updateBuffer(); + mChannels[i]->update3DPosition(); + mChannels[i]->updateLoop(); + } + } } void LLAudioEngine::idle() { - // "Update" all of our audio sources, clean up dead ones. - // Primarily does position updating, cleanup of unused audio sources. - // Also does regeneration of the current priority of each audio source. - - S32 i; - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - if (mBuffers[i]) - { - mBuffers[i]->mInUse = false; - } - } - - F32 max_priority = -1.f; - LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel - source_map::iterator iter; - for (iter = mAllSources.begin(); iter != mAllSources.end();) - { - LLAudioSource *sourcep = iter->second; - - // Update this source - sourcep->update(); - sourcep->updatePriority(); - - if (sourcep->isDone()) - { - // The source is done playing, clean it up. - delete sourcep; + // "Update" all of our audio sources, clean up dead ones. + // Primarily does position updating, cleanup of unused audio sources. + // Also does regeneration of the current priority of each audio source. + + S32 i; + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + if (mBuffers[i]) + { + mBuffers[i]->mInUse = false; + } + } + + F32 max_priority = -1.f; + LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel + source_map::iterator iter; + for (iter = mAllSources.begin(); iter != mAllSources.end();) + { + LLAudioSource *sourcep = iter->second; + + // Update this source + sourcep->update(); + sourcep->updatePriority(); + + if (sourcep->isDone()) + { + // The source is done playing, clean it up. + delete sourcep; iter = mAllSources.erase(iter); - continue; - } - - if (sourcep->isMuted()) - { - ++iter; - continue; - } - - if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) - { - // We could potentially play this sound if its priority is high enough. - if (sourcep->getPriority() > max_priority) - { - max_priority = sourcep->getPriority(); - max_sourcep = sourcep; - } - } - - // Move on to the next source - iter++; - } - - // Now, do priority-based organization of audio sources. - // All channels used, check priorities. - // Find channel with lowest priority - if (max_sourcep) - { - LLAudioChannel *channelp = getFreeChannel(max_priority); - if (channelp) - { - //LL_INFOS() << "Replacing source in channel due to priority!" << LL_ENDL; - max_sourcep->setChannel(channelp); - channelp->setSource(max_sourcep); - if (max_sourcep->isSyncSlave()) - { - // A sync slave, it doesn't start playing until it's synced up with the master. - // Flag this channel as waiting for sync, and return true. - channelp->setWaiting(true); - } - else - { - channelp->setWaiting(false); - channelp->play(); - } - } - } - - - // Do this BEFORE we update the channels - // Update the channels to sync up with any changes that the source made, - // such as changing what sound was playing. - updateChannels(); - - // Update queued sounds (switch to next queued data if the current has finished playing) - for (source_map::value_type& src_pair : mAllSources) - { - // This is lame, instead of this I could actually iterate through all the sources - // attached to each channel, since only those with active channels - // can have anything interesting happen with their queue? (Maybe not true) - LLAudioSource *sourcep = src_pair.second; - if (!sourcep->mQueuedDatap || sourcep->isMuted()) - { - // Muted, or nothing queued, so we don't care. - continue; - } - - LLAudioChannel *channelp = sourcep->getChannel(); - if (!channelp) - { - // This sound isn't playing, so we just process move the queue - sourcep->mCurrentDatap = sourcep->mQueuedDatap; - sourcep->mQueuedDatap = NULL; - - // Reset the timer so the source doesn't die. - sourcep->mAgeTimer.reset(); - // Make sure we have the buffer set up if we just decoded the data - if (sourcep->mCurrentDatap) - { - updateBufferForData(sourcep->mCurrentDatap); - } - - // Actually play the associated data. - sourcep->setupChannel(); - channelp = sourcep->getChannel(); - if (channelp) - { - channelp->updateBuffer(); - sourcep->getChannel()->play(); - } - continue; - } - - // Check to see if the current sound is done playing. - if (!channelp->isPlaying()) - { - sourcep->mCurrentDatap = sourcep->mQueuedDatap; - sourcep->mQueuedDatap = NULL; - - // Reset the timer so the source doesn't die. - sourcep->mAgeTimer.reset(); - - // Make sure we have the buffer set up if we just decoded the data - if (sourcep->mCurrentDatap) - { - updateBufferForData(sourcep->mCurrentDatap); - } - - // Actually play the associated data. - sourcep->setupChannel(); - channelp->updateBuffer(); - sourcep->getChannel()->play(); - continue; - } - - // Check to see if the current sound is looped. - if (sourcep->isLoop()) - { - // It's a loop, we need to check and see if we're done with it. - if (channelp->mLoopedThisFrame) - { - sourcep->mCurrentDatap = sourcep->mQueuedDatap; - sourcep->mQueuedDatap = NULL; - - // Actually, should do a time sync so if we're a loop master/slave - // we don't drift away. - sourcep->setupChannel(); - sourcep->getChannel()->play(); - } - } - } - - // Lame, update the channels AGAIN. - // Update the channels to sync up with any changes that the source made, - // such as changing what sound was playing. - updateChannels(); - - // Hack! For now, just use a global sync master; - LLAudioSource *sync_masterp = NULL; - LLAudioChannel *master_channelp = NULL; - F32 max_sm_priority = -1.f; - for (source_map::value_type& src_pair : mAllSources) - { - LLAudioSource *sourcep = src_pair.second; - if (!sourcep->isMuted() && sourcep->isSyncMaster() && sourcep->getPriority() > max_sm_priority) - { - sync_masterp = sourcep; - master_channelp = sync_masterp->getChannel(); - max_sm_priority = sourcep->getPriority(); - } - } - - if (master_channelp && master_channelp->mLoopedThisFrame) - { - // Synchronize loop slaves with their masters - // Update queued sounds (switch to next queued data if the current has finished playing) - for (source_map::value_type& src_pair : mAllSources) - { - LLAudioSource *sourcep = src_pair.second; - - if (!sourcep->isSyncSlave()) - { - // Not a loop slave, we don't need to do anything - continue; - } - - LLAudioChannel *channelp = sourcep->getChannel(); - if (!channelp) - { - // Not playing, don't need to bother. - continue; - } - - if (!channelp->isPlaying()) - { - // Now we need to check if our loop master has just looped, and - // start playback if that's the case. - if (sync_masterp->getChannel()) - { - channelp->playSynced(master_channelp); - channelp->setWaiting(false); - } - } - } - } - - // Sync up everything that the audio engine needs done. - commitDeferredChanges(); - - // Flush unused buffers that are stale enough - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - if (mBuffers[i]) - { - if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) - { - //LL_INFOS() << "Flushing unused buffer!" << LL_ENDL; - mBuffers[i]->mAudioDatap->mBufferp = NULL; - delete mBuffers[i]; - mBuffers[i] = NULL; - } - } - } - - - // Clear all of the looped flags for the channels - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (mChannels[i]) - { - mChannels[i]->mLoopedThisFrame = false; - } - } - - // Decode audio files + continue; + } + + if (sourcep->isMuted()) + { + ++iter; + continue; + } + + if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) + { + // We could potentially play this sound if its priority is high enough. + if (sourcep->getPriority() > max_priority) + { + max_priority = sourcep->getPriority(); + max_sourcep = sourcep; + } + } + + // Move on to the next source + iter++; + } + + // Now, do priority-based organization of audio sources. + // All channels used, check priorities. + // Find channel with lowest priority + if (max_sourcep) + { + LLAudioChannel *channelp = getFreeChannel(max_priority); + if (channelp) + { + //LL_INFOS() << "Replacing source in channel due to priority!" << LL_ENDL; + max_sourcep->setChannel(channelp); + channelp->setSource(max_sourcep); + if (max_sourcep->isSyncSlave()) + { + // A sync slave, it doesn't start playing until it's synced up with the master. + // Flag this channel as waiting for sync, and return true. + channelp->setWaiting(true); + } + else + { + channelp->setWaiting(false); + channelp->play(); + } + } + } + + + // Do this BEFORE we update the channels + // Update the channels to sync up with any changes that the source made, + // such as changing what sound was playing. + updateChannels(); + + // Update queued sounds (switch to next queued data if the current has finished playing) + for (source_map::value_type& src_pair : mAllSources) + { + // This is lame, instead of this I could actually iterate through all the sources + // attached to each channel, since only those with active channels + // can have anything interesting happen with their queue? (Maybe not true) + LLAudioSource *sourcep = src_pair.second; + if (!sourcep->mQueuedDatap || sourcep->isMuted()) + { + // Muted, or nothing queued, so we don't care. + continue; + } + + LLAudioChannel *channelp = sourcep->getChannel(); + if (!channelp) + { + // This sound isn't playing, so we just process move the queue + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Reset the timer so the source doesn't die. + sourcep->mAgeTimer.reset(); + // Make sure we have the buffer set up if we just decoded the data + if (sourcep->mCurrentDatap) + { + updateBufferForData(sourcep->mCurrentDatap); + } + + // Actually play the associated data. + sourcep->setupChannel(); + channelp = sourcep->getChannel(); + if (channelp) + { + channelp->updateBuffer(); + sourcep->getChannel()->play(); + } + continue; + } + + // Check to see if the current sound is done playing. + if (!channelp->isPlaying()) + { + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Reset the timer so the source doesn't die. + sourcep->mAgeTimer.reset(); + + // Make sure we have the buffer set up if we just decoded the data + if (sourcep->mCurrentDatap) + { + updateBufferForData(sourcep->mCurrentDatap); + } + + // Actually play the associated data. + sourcep->setupChannel(); + channelp->updateBuffer(); + sourcep->getChannel()->play(); + continue; + } + + // Check to see if the current sound is looped. + if (sourcep->isLoop()) + { + // It's a loop, we need to check and see if we're done with it. + if (channelp->mLoopedThisFrame) + { + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Actually, should do a time sync so if we're a loop master/slave + // we don't drift away. + sourcep->setupChannel(); + sourcep->getChannel()->play(); + } + } + } + + // Lame, update the channels AGAIN. + // Update the channels to sync up with any changes that the source made, + // such as changing what sound was playing. + updateChannels(); + + // Hack! For now, just use a global sync master; + LLAudioSource *sync_masterp = NULL; + LLAudioChannel *master_channelp = NULL; + F32 max_sm_priority = -1.f; + for (source_map::value_type& src_pair : mAllSources) + { + LLAudioSource *sourcep = src_pair.second; + if (!sourcep->isMuted() && sourcep->isSyncMaster() && sourcep->getPriority() > max_sm_priority) + { + sync_masterp = sourcep; + master_channelp = sync_masterp->getChannel(); + max_sm_priority = sourcep->getPriority(); + } + } + + if (master_channelp && master_channelp->mLoopedThisFrame) + { + // Synchronize loop slaves with their masters + // Update queued sounds (switch to next queued data if the current has finished playing) + for (source_map::value_type& src_pair : mAllSources) + { + LLAudioSource *sourcep = src_pair.second; + + if (!sourcep->isSyncSlave()) + { + // Not a loop slave, we don't need to do anything + continue; + } + + LLAudioChannel *channelp = sourcep->getChannel(); + if (!channelp) + { + // Not playing, don't need to bother. + continue; + } + + if (!channelp->isPlaying()) + { + // Now we need to check if our loop master has just looped, and + // start playback if that's the case. + if (sync_masterp->getChannel()) + { + channelp->playSynced(master_channelp); + channelp->setWaiting(false); + } + } + } + } + + // Sync up everything that the audio engine needs done. + commitDeferredChanges(); + + // Flush unused buffers that are stale enough + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + if (mBuffers[i]) + { + if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) + { + //LL_INFOS() << "Flushing unused buffer!" << LL_ENDL; + mBuffers[i]->mAudioDatap->mBufferp = NULL; + delete mBuffers[i]; + mBuffers[i] = NULL; + } + } + } + + + // Clear all of the looped flags for the channels + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + if (mChannels[i]) + { + mChannels[i]->mLoopedThisFrame = false; + } + } + + // Decode audio files LLAudioDecodeMgr::getInstance()->processQueue(); - - // Call this every frame, just in case we somehow - // missed picking it up in all the places that can add - // or request new data. - startNextTransfer(); - updateInternetStream(); + // Call this every frame, just in case we somehow + // missed picking it up in all the places that can add + // or request new data. + startNextTransfer(); + + updateInternetStream(); } bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid) { - if (!adp) - { - return false; - } - - // Update the audio buffer first - load a sound if we have it. - // Note that this could potentially cause us to waste time updating buffers - // for sounds that actually aren't playing, although this should be mitigated - // by the fact that we limit the number of buffers, and we flush buffers based - // on priority. - if (!adp->getBuffer()) - { - if (adp->hasDecodedData()) - { - adp->load(); - } - else if (adp->hasLocalData()) - { - if (audio_uuid.notNull()) - { + if (!adp) + { + return false; + } + + // Update the audio buffer first - load a sound if we have it. + // Note that this could potentially cause us to waste time updating buffers + // for sounds that actually aren't playing, although this should be mitigated + // by the fact that we limit the number of buffers, and we flush buffers based + // on priority. + if (!adp->getBuffer()) + { + if (adp->hasDecodedData()) + { + adp->load(); + } + else if (adp->hasLocalData()) + { + if (audio_uuid.notNull()) + { LLAudioDecodeMgr::getInstance()->addDecodeRequest(audio_uuid); - } - } - else - { - return false; - } - } - return true; + } + } + else + { + return false; + } + } + return true; } void LLAudioEngine::enableWind(bool enable) { - if (enable && (!mEnableWind)) - { - mEnableWind = initWind(); - } - else if (mEnableWind && (!enable)) - { - mEnableWind = false; - cleanupWind(); - } + if (enable && (!mEnableWind)) + { + mEnableWind = initWind(); + } + else if (mEnableWind && (!enable)) + { + mEnableWind = false; + cleanupWind(); + } } LLAudioBuffer * LLAudioEngine::getFreeBuffer() { - S32 i; - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - if (!mBuffers[i]) - { - mBuffers[i] = createBuffer(); - return mBuffers[i]; - } - } - - - // Grab the oldest unused buffer - F32 max_age = -1.f; - S32 buffer_id = -1; - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - if (mBuffers[i]) - { - if (!mBuffers[i]->mInUse) - { - if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age) - { - max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32(); - buffer_id = i; - } - } - } - } - - if (buffer_id >= 0) - { - LL_DEBUGS() << "Taking over unused buffer " << buffer_id << LL_ENDL; - //LL_INFOS() << "Flushing unused buffer!" << LL_ENDL; - mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL; - delete mBuffers[buffer_id]; - mBuffers[buffer_id] = createBuffer(); - return mBuffers[buffer_id]; - } - return NULL; + S32 i; + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + if (!mBuffers[i]) + { + mBuffers[i] = createBuffer(); + return mBuffers[i]; + } + } + + + // Grab the oldest unused buffer + F32 max_age = -1.f; + S32 buffer_id = -1; + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + if (mBuffers[i]) + { + if (!mBuffers[i]->mInUse) + { + if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age) + { + max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32(); + buffer_id = i; + } + } + } + } + + if (buffer_id >= 0) + { + LL_DEBUGS() << "Taking over unused buffer " << buffer_id << LL_ENDL; + //LL_INFOS() << "Flushing unused buffer!" << LL_ENDL; + mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL; + delete mBuffers[buffer_id]; + mBuffers[buffer_id] = createBuffer(); + return mBuffers[buffer_id]; + } + return NULL; } LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) { - S32 i; + S32 i; for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (!mChannels[i]) - { - // No channel allocated here, use it. - mChannels[i] = createChannel(); - return mChannels[i]; - } - else - { - // Channel is allocated but not playing right now, use it. - if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) - { - mChannels[i]->cleanup(); - if (mChannels[i]->getSource()) - { - mChannels[i]->getSource()->setChannel(NULL); - } - return mChannels[i]; - } - } - } - - // All channels used, check priorities. - // Find channel with lowest priority and see if we want to replace it. - F32 min_priority = 10000.f; - LLAudioChannel *min_channelp = NULL; + { + if (!mChannels[i]) + { + // No channel allocated here, use it. + mChannels[i] = createChannel(); + return mChannels[i]; + } + else + { + // Channel is allocated but not playing right now, use it. + if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) + { + mChannels[i]->cleanup(); + if (mChannels[i]->getSource()) + { + mChannels[i]->getSource()->setChannel(NULL); + } + return mChannels[i]; + } + } + } + + // All channels used, check priorities. + // Find channel with lowest priority and see if we want to replace it. + F32 min_priority = 10000.f; + LLAudioChannel *min_channelp = NULL; for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - LLAudioChannel *channelp = mChannels[i]; - LLAudioSource *sourcep = channelp->getSource(); - if (sourcep->getPriority() < min_priority) - { - min_channelp = channelp; - min_priority = sourcep->getPriority(); - } - } + { + LLAudioChannel *channelp = mChannels[i]; + LLAudioSource *sourcep = channelp->getSource(); + if (sourcep->getPriority() < min_priority) + { + min_channelp = channelp; + min_priority = sourcep->getPriority(); + } + } - if (min_priority > priority || !min_channelp) - { - // All playing channels have higher priority, return. - return NULL; - } + if (min_priority > priority || !min_channelp) + { + // All playing channels have higher priority, return. + return NULL; + } - // Flush the minimum priority channel, and return it. - min_channelp->cleanup(); - min_channelp->getSource()->setChannel(NULL); - return min_channelp; + // Flush the minimum priority channel, and return it. + min_channelp->cleanup(); + min_channelp->getSource()->setChannel(NULL); + return min_channelp; } void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp) { - S32 i; - for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) - { - if (mBuffers[i] == bufferp) - { - delete mBuffers[i]; - mBuffers[i] = NULL; - } - } + S32 i; + for (i = 0; i < LL_MAX_AUDIO_BUFFERS; i++) + { + if (mBuffers[i] == bufferp) + { + delete mBuffers[i]; + mBuffers[i] = NULL; + } + } } bool LLAudioEngine::preloadSound(const LLUUID &uuid) { - LL_DEBUGS("AudioEngine")<<"( "<<uuid<<" )"<<LL_ENDL; + LL_DEBUGS("AudioEngine")<<"( "<<uuid<<" )"<<LL_ENDL; - getAudioData(uuid); // We don't care about the return value, this is just to make sure - // that we have an entry, which will mean that the audio engine knows about this + getAudioData(uuid); // We don't care about the return value, this is just to make sure + // that we have an entry, which will mean that the audio engine knows about this if (LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid)) - { - // This means that we do have a local copy, and we're working on decoding it. - return true; - } + { + // This means that we do have a local copy, and we're working on decoding it. + return true; + } - return false; + return false; } bool LLAudioEngine::isWindEnabled() { - return mEnableWind; + return mEnableWind; } void LLAudioEngine::setMuted(bool muted) { - if (muted != mMuted) - { - mMuted = muted; - setMasterGain(mMasterGain); - } - enableWind(!mMuted); + if (muted != mMuted) + { + mMuted = muted; + setMasterGain(mMasterGain); + } + enableWind(!mMuted); } void LLAudioEngine::setMasterGain(const F32 gain) { - mMasterGain = gain; - F32 internal_gain = getMuted() ? 0.f : gain; - if (internal_gain != mInternalGain) - { - mInternalGain = internal_gain; - setInternalGain(mInternalGain); - } + mMasterGain = gain; + F32 internal_gain = getMuted() ? 0.f : gain; + if (internal_gain != mInternalGain) + { + mInternalGain = internal_gain; + setInternalGain(mInternalGain); + } } F32 LLAudioEngine::getMasterGain() { - return mMasterGain; + return mMasterGain; } void LLAudioEngine::setSecondaryGain(S32 type, F32 gain) { - llassert(type < LLAudioEngine::AUDIO_TYPE_COUNT); - - mSecondaryGain[type] = gain; + llassert(type < LLAudioEngine::AUDIO_TYPE_COUNT); + + mSecondaryGain[type] = gain; } F32 LLAudioEngine::getSecondaryGain(S32 type) { - return mSecondaryGain[type]; + return mSecondaryGain[type]; } F32 LLAudioEngine::getInternetStreamGain() { - if (mStreamingAudioImpl) - return mStreamingAudioImpl->getGain(); - else - return 1.0f; + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getGain(); + else + return 1.0f; } void LLAudioEngine::setMaxWindGain(F32 gain) { - mMaxWindGain = gain; + mMaxWindGain = gain; } F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec) { - F64 gain = 0.0; - - gain = wind_vec.magVec(); + F64 gain = 0.0; - if (gain) - { - if (gain > 20) - { - gain = 20; - } - gain = gain/20.0; - } + gain = wind_vec.magVec(); + + if (gain) + { + if (gain > 20) + { + gain = 20; + } + gain = gain/20.0; + } - return (gain); + return (gain); } F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec) { - LLVector3 listen_right; - F64 theta; - - // Wind frame is in listener-relative coordinates - LLVector3 norm_wind = wind_vec; - norm_wind.normVec(); - listen_right.setVec(1.0,0.0,0.0); + LLVector3 listen_right; + F64 theta; - // measure angle between wind vec and listener right axis (on 0,PI) - theta = acos(norm_wind * listen_right); + // Wind frame is in listener-relative coordinates + LLVector3 norm_wind = wind_vec; + norm_wind.normVec(); + listen_right.setVec(1.0,0.0,0.0); - // put it on 0, 1 - theta /= F_PI; + // measure angle between wind vec and listener right axis (on 0,PI) + theta = acos(norm_wind * listen_right); - // put it on [0, 0.5, 0] - if (theta > 0.5) theta = 1.0-theta; - if (theta < 0) theta = 0; + // put it on 0, 1 + theta /= F_PI; - return (theta); + // put it on [0, 0.5, 0] + if (theta > 0.5) theta = 1.0-theta; + if (theta < 0) theta = 0; + + return (theta); } F64 LLAudioEngine::mapWindVecToPan(LLVector3 wind_vec) { - LLVector3 listen_right; - F64 theta; - - // Wind frame is in listener-relative coordinates - listen_right.setVec(1.0,0.0,0.0); + LLVector3 listen_right; + F64 theta; + + // Wind frame is in listener-relative coordinates + listen_right.setVec(1.0,0.0,0.0); - LLVector3 norm_wind = wind_vec; - norm_wind.normVec(); + LLVector3 norm_wind = wind_vec; + norm_wind.normVec(); - // measure angle between wind vec and listener right axis (on 0,PI) - theta = acos(norm_wind * listen_right); + // measure angle between wind vec and listener right axis (on 0,PI) + theta = acos(norm_wind * listen_right); - // put it on 0, 1 - theta /= F_PI; + // put it on 0, 1 + theta /= F_PI; - return (theta); + return (theta); } void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, - const S32 type, const LLVector3d &pos_global) -{ - // Create a new source (since this can't be associated with an existing source. - //LL_INFOS() << "Localized: " << audio_uuid << LL_ENDL; - - if (mMuted) - { - return; - } - - LLUUID source_id; - source_id.generate(); - - LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type); - addAudioSource(asp); - if (pos_global.isExactlyZero()) - { - // For sound preview and UI - asp->setForcedPriority(true); - } - else - { - asp->setPositionGlobal(pos_global); - } - asp->updatePriority(); - asp->play(audio_uuid); + const S32 type, const LLVector3d &pos_global) +{ + // Create a new source (since this can't be associated with an existing source. + //LL_INFOS() << "Localized: " << audio_uuid << LL_ENDL; + + if (mMuted) + { + return; + } + + LLUUID source_id; + source_id.generate(); + + LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type); + addAudioSource(asp); + if (pos_global.isExactlyZero()) + { + // For sound preview and UI + asp->setForcedPriority(true); + } + else + { + asp->setPositionGlobal(pos_global); + } + asp->updatePriority(); + asp->play(audio_uuid); } void LLAudioEngine::triggerSound(SoundData& soundData) { - triggerSound(soundData.audio_uuid, soundData.owner_id, soundData.gain, soundData.type, soundData.pos_global); + triggerSound(soundData.audio_uuid, soundData.owner_id, soundData.gain, soundData.type, soundData.pos_global); } void LLAudioEngine::setListenerPos(LLVector3 aVec) { - mListenerp->setPosition(aVec); + mListenerp->setPosition(aVec); } LLVector3 LLAudioEngine::getListenerPos() { - if (mListenerp) - { - return(mListenerp->getPosition()); - } - else - { - return(LLVector3::zero); - } + if (mListenerp) + { + return(mListenerp->getPosition()); + } + else + { + return(LLVector3::zero); + } } void LLAudioEngine::setListenerVelocity(LLVector3 aVec) { - mListenerp->setVelocity(aVec); + mListenerp->setVelocity(aVec); } void LLAudioEngine::translateListener(LLVector3 aVec) { - mListenerp->translate(aVec); + mListenerp->translate(aVec); } void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at) { - mListenerp->orient(up, at); + mListenerp->orient(up, at); } void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) { - mListenerp->set(pos,vel,up,at); + mListenerp->set(pos,vel,up,at); } void LLAudioEngine::setDopplerFactor(F32 factor) { - if (mListenerp) - { - mListenerp->setDopplerFactor(factor); - } + if (mListenerp) + { + mListenerp->setDopplerFactor(factor); + } } F32 LLAudioEngine::getDopplerFactor() { - if (mListenerp) - { - return mListenerp->getDopplerFactor(); - } - else - { - return 0.f; - } + if (mListenerp) + { + return mListenerp->getDopplerFactor(); + } + else + { + return 0.f; + } } void LLAudioEngine::setRolloffFactor(F32 factor) { - if (mListenerp) - { - mListenerp->setRolloffFactor(factor); - } + if (mListenerp) + { + mListenerp->setRolloffFactor(factor); + } } F32 LLAudioEngine::getRolloffFactor() { - if (mListenerp) - { - return mListenerp->getRolloffFactor(); - } - else - { - return 0.f; - } + if (mListenerp) + { + return mListenerp->getRolloffFactor(); + } + else + { + return 0.f; + } } void LLAudioEngine::commitDeferredChanges() { - mListenerp->commitDeferredChanges(); + mListenerp->commitDeferredChanges(); } LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id) { - source_map::iterator iter; - iter = mAllSources.find(source_id); + source_map::iterator iter; + iter = mAllSources.find(source_id); - if (iter == mAllSources.end()) - { - return NULL; - } - else - { - return iter->second; - } + if (iter == mAllSources.end()) + { + return NULL; + } + else + { + return iter->second; + } } LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - data_map::iterator iter; - iter = mAllData.find(audio_uuid); - if (iter == mAllData.end()) - { - // Create the new audio data - LLAudioData *adp = new LLAudioData(audio_uuid); - mAllData[audio_uuid] = adp; - return adp; - } - else - { - return iter->second; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; + data_map::iterator iter; + iter = mAllData.find(audio_uuid); + if (iter == mAllData.end()) + { + // Create the new audio data + LLAudioData *adp = new LLAudioData(audio_uuid); + mAllData[audio_uuid] = adp; + return adp; + } + else + { + return iter->second; + } } void LLAudioEngine::addAudioSource(LLAudioSource *asp) { - mAllSources[asp->getID()] = asp; + mAllSources[asp->getID()] = asp; } void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp) { - source_map::iterator iter; - iter = mAllSources.find(asp->getID()); - if (iter == mAllSources.end()) - { - LL_WARNS() << "Cleaning up unknown audio source!" << LL_ENDL; - return; - } - else - { - LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <<LL_ENDL; - delete asp; - mAllSources.erase(iter); - } + source_map::iterator iter; + iter = mAllSources.find(asp->getID()); + if (iter == mAllSources.end()) + { + LL_WARNS() << "Cleaning up unknown audio source!" << LL_ENDL; + return; + } + else + { + LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <<LL_ENDL; + delete asp; + mAllSources.erase(iter); + } } bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid) { - std::string uuid_str; - uuid.toString(uuid_str); + std::string uuid_str; + uuid.toString(uuid_str); - std::string wav_path; - wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str); - wav_path += ".dsf"; + std::string wav_path; + wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str); + wav_path += ".dsf"; - if (gDirUtilp->fileExists(wav_path)) - { - return true; - } - else - { - return false; - } + if (gDirUtilp->fileExists(wav_path)) + { + return true; + } + else + { + return false; + } } bool LLAudioEngine::hasLocalFile(const LLUUID &uuid) { - // See if it's in the cache. - bool have_local = LLFileSystem::getExists(uuid, LLAssetType::AT_SOUND); - LL_DEBUGS("AudioEngine") << "sound uuid " << uuid << " exists in cache" << LL_ENDL; - return have_local; + // See if it's in the cache. + bool have_local = LLFileSystem::getExists(uuid, LLAssetType::AT_SOUND); + LL_DEBUGS("AudioEngine") << "sound uuid " << uuid << " exists in cache" << LL_ENDL; + return have_local; } void LLAudioEngine::startNextTransfer() { - //LL_INFOS() << "LLAudioEngine::startNextTransfer()" << LL_ENDL; - if (mCurrentTransfer.notNull() || getMuted()) - { - //LL_INFOS() << "Transfer in progress, aborting" << LL_ENDL; - return; - } - - // Get the ID for the next asset that we want to transfer. - // Pick one in the following order: - LLUUID asset_id; - S32 i; - LLAudioSource *asp = NULL; - LLAudioData *adp = NULL; - data_map::iterator data_iter; - - // Check all channels for currently playing sounds. - F32 max_pri = -1.f; - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (!mChannels[i]) - { - continue; - } - - asp = mChannels[i]->getSource(); - if (!asp) - { - continue; - } - if (asp->getPriority() <= max_pri) - { - continue; - } - - if (asp->getPriority() <= max_pri) - { - continue; - } - - adp = asp->getCurrentData(); - if (!adp) - { - continue; - } + //LL_INFOS() << "LLAudioEngine::startNextTransfer()" << LL_ENDL; + if (mCurrentTransfer.notNull() || getMuted()) + { + //LL_INFOS() << "Transfer in progress, aborting" << LL_ENDL; + return; + } + + // Get the ID for the next asset that we want to transfer. + // Pick one in the following order: + LLUUID asset_id; + S32 i; + LLAudioSource *asp = NULL; + LLAudioData *adp = NULL; + data_map::iterator data_iter; + + // Check all channels for currently playing sounds. + F32 max_pri = -1.f; + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + if (asp->getPriority() <= max_pri) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getCurrentData(); + if (!adp) + { + continue; + } if (!adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - } - } - - // Check all channels for currently queued sounds. - if (asset_id.isNull()) - { - max_pri = -1.f; - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (!mChannels[i]) - { - continue; - } - - LLAudioSource *asp; - asp = mChannels[i]->getSource(); - if (!asp) - { - continue; - } - - if (asp->getPriority() <= max_pri) - { - continue; - } - - adp = asp->getQueuedData(); - if (!adp) - { - continue; - } + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + + // Check all channels for currently queued sounds. + if (asset_id.isNull()) + { + max_pri = -1.f; + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + LLAudioSource *asp; + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getQueuedData(); + if (!adp) + { + continue; + } if (!adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - } - } - } - - // Check all live channels for other sounds (preloads). - if (asset_id.isNull()) - { - max_pri = -1.f; - for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) - { - if (!mChannels[i]) - { - continue; - } - - LLAudioSource *asp; - asp = mChannels[i]->getSource(); - if (!asp) - { - continue; - } - - if (asp->getPriority() <= max_pri) - { - continue; - } - - - for (data_map::value_type& preload_pair : asp->mPreloadMap) - { - LLAudioData *adp = preload_pair.second; - if (!adp) - { - continue; - } + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + } + + // Check all live channels for other sounds (preloads). + if (asset_id.isNull()) + { + max_pri = -1.f; + for (i = 0; i < LL_MAX_AUDIO_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + LLAudioSource *asp; + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + + for (data_map::value_type& preload_pair : asp->mPreloadMap) + { + LLAudioData *adp = preload_pair.second; + if (!adp) + { + continue; + } if (!adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - } - } - } - } - - // Check all sources - if (asset_id.isNull()) - { - max_pri = -1.f; - source_map::iterator source_iter; - for (source_map::value_type& source_pair : mAllSources) - { - asp = source_pair.second; - if (!asp) - { - continue; - } - - if (asp->getPriority() <= max_pri) - { - continue; - } - - adp = asp->getCurrentData(); + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + } + } + + // Check all sources + if (asset_id.isNull()) + { + max_pri = -1.f; + source_map::iterator source_iter; + for (source_map::value_type& source_pair : mAllSources) + { + asp = source_pair.second; + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getCurrentData(); if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - continue; - } + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + continue; + } - adp = asp->getQueuedData(); + adp = asp->getQueuedData(); if (adp && !adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - continue; - } - - for (data_map::value_type& preload_pair : asp->mPreloadMap) - { - LLAudioData *adp = preload_pair.second; - if (!adp) - { - continue; - } + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + continue; + } + + for (data_map::value_type& preload_pair : asp->mPreloadMap) + { + LLAudioData *adp = preload_pair.second; + if (!adp) + { + continue; + } if (!adp->hasLocalData() && !adp->hasDecodeFailed()) - { - asset_id = adp->getID(); - max_pri = asp->getPriority(); - break; - } - } - } - } - - if (asset_id.notNull()) - { - LL_INFOS() << "Getting asset data for: " << asset_id << LL_ENDL; - mCurrentTransfer = asset_id; - mCurrentTransferTimer.reset(); - gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, - assetCallback, NULL); - } - else - { - //LL_INFOS() << "No pending transfers?" << LL_ENDL; - } + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + break; + } + } + } + } + + if (asset_id.notNull()) + { + LL_INFOS() << "Getting asset data for: " << asset_id << LL_ENDL; + mCurrentTransfer = asset_id; + mCurrentTransferTimer.reset(); + gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, + assetCallback, NULL); + } + else + { + //LL_INFOS() << "No pending transfers?" << LL_ENDL; + } } // static void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status) { - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return; - } - - if (result_code) - { - LL_INFOS() << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << LL_ENDL; - // Need to mark data as bad to avoid constant rerequests. - LLAudioData *adp = gAudiop->getAudioData(uuid); - if (adp) - { // Make sure everything is cleared + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } + + if (result_code) + { + LL_INFOS() << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << LL_ENDL; + // Need to mark data as bad to avoid constant rerequests. + LLAudioData *adp = gAudiop->getAudioData(uuid); + if (adp) + { // Make sure everything is cleared adp->setHasDecodeFailed(true); - adp->setHasLocalData(false); - adp->setHasDecodedData(false); - adp->setHasCompletedDecode(true); - } - } - else - { - LLAudioData *adp = gAudiop->getAudioData(uuid); - if (!adp) + adp->setHasLocalData(false); + adp->setHasDecodedData(false); + adp->setHasCompletedDecode(true); + } + } + else + { + LLAudioData *adp = gAudiop->getAudioData(uuid); + if (!adp) { - // Should never happen - LL_WARNS() << "Got asset callback without audio data for " << uuid << LL_ENDL; + // Should never happen + LL_WARNS() << "Got asset callback without audio data for " << uuid << LL_ENDL; } - else - { - // LL_INFOS() << "Got asset callback with good audio data for " << uuid << ", making decode request" << LL_ENDL; + else + { + // LL_INFOS() << "Got asset callback with good audio data for " << uuid << ", making decode request" << LL_ENDL; adp->setHasDecodeFailed(false); - adp->setHasLocalData(true); + adp->setHasLocalData(true); LLAudioDecodeMgr::getInstance()->addDecodeRequest(uuid); - } - } - gAudiop->mCurrentTransfer = LLUUID::null; - gAudiop->startNextTransfer(); + } + } + gAudiop->mCurrentTransfer = LLUUID::null; + gAudiop->startNextTransfer(); } @@ -1240,142 +1240,142 @@ void LLAudioEngine::assetCallback(const LLUUID &uuid, LLAssetType::EType type, v LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 gain, const S32 type) -: mID(id), - mOwnerID(owner_id), - mPriority(0.f), - mGain(gain), - mSourceMuted(false), - mForcedPriority(false), - mLoop(false), - mSyncMaster(false), - mSyncSlave(false), - mQueueSounds(false), - mPlayedOnce(false), - mCorrupted(false), - mType(type), - mChannelp(NULL), - mCurrentDatap(NULL), - mQueuedDatap(NULL) +: mID(id), + mOwnerID(owner_id), + mPriority(0.f), + mGain(gain), + mSourceMuted(false), + mForcedPriority(false), + mLoop(false), + mSyncMaster(false), + mSyncSlave(false), + mQueueSounds(false), + mPlayedOnce(false), + mCorrupted(false), + mType(type), + mChannelp(NULL), + mCurrentDatap(NULL), + mQueuedDatap(NULL) { } LLAudioSource::~LLAudioSource() { - if (mChannelp) - { - // Stop playback of this sound - mChannelp->setSource(NULL); - mChannelp = NULL; - } + if (mChannelp) + { + // Stop playback of this sound + mChannelp->setSource(NULL); + mChannelp = NULL; + } } void LLAudioSource::setChannel(LLAudioChannel *channelp) { - if (channelp == mChannelp) - { - return; - } + if (channelp == mChannelp) + { + return; + } - mChannelp = channelp; + mChannelp = channelp; } void LLAudioSource::update() { - if(mCorrupted) - { - return ; //no need to update - } - - if (!getCurrentBuffer()) - { - LLAudioData *adp = getCurrentData(); - if (adp) - { - // Hack - try and load the sound. Will do this as a callback - // on decode later. + if(mCorrupted) + { + return ; //no need to update + } + + if (!getCurrentBuffer()) + { + LLAudioData *adp = getCurrentData(); + if (adp) + { + // Hack - try and load the sound. Will do this as a callback + // on decode later. if (adp->getBuffer()) - { - play(adp->getID()); - } + { + play(adp->getID()); + } else if (adp->hasDecodedData() && !adp->hasWAVLoadFailed()) { adp->load(); } else if (adp->hasCompletedDecode() && adp->hasDecodeFailed()) // Only mark corrupted after decode is done - { - LL_WARNS() << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL; - mCorrupted = true ; - } - } - } + { + LL_WARNS() << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL; + mCorrupted = true ; + } + } + } } void LLAudioSource::updatePriority() { - if (isForcedPriority()) - { - mPriority = 1.f; - } - else if (isMuted()) - { - mPriority = 0.f; - } - else - { - // Priority is based on distance - LLVector3 dist_vec; - dist_vec.setVec(getPositionGlobal()); + if (isForcedPriority()) + { + mPriority = 1.f; + } + else if (isMuted()) + { + mPriority = 0.f; + } + else + { + // Priority is based on distance + LLVector3 dist_vec; + dist_vec.setVec(getPositionGlobal()); - if (gAudiop) - { - dist_vec -= gAudiop->getListenerPos(); - } + if (gAudiop) + { + dist_vec -= gAudiop->getListenerPos(); + } - F32 dist_squared = llmax(1.f, dist_vec.magVecSquared()); + F32 dist_squared = llmax(1.f, dist_vec.magVecSquared()); - mPriority = mGain / dist_squared; - } + mPriority = mGain / dist_squared; + } } bool LLAudioSource::setupChannel() { - LLAudioData *adp = getCurrentData(); + LLAudioData *adp = getCurrentData(); - if (!adp->getBuffer()) - { - // We're not ready to play back the sound yet, so don't try and allocate a channel for it. - //LL_WARNS() << "Aborting, no buffer" << LL_ENDL; - return false; - } + if (!adp->getBuffer()) + { + // We're not ready to play back the sound yet, so don't try and allocate a channel for it. + //LL_WARNS() << "Aborting, no buffer" << LL_ENDL; + return false; + } - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return false; - } + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return false; + } - if (!mChannelp) - { - // Update the priority, in case we need to push out another channel. - updatePriority(); + if (!mChannelp) + { + // Update the priority, in case we need to push out another channel. + updatePriority(); - setChannel(gAudiop->getFreeChannel(getPriority())); - } + setChannel(gAudiop->getFreeChannel(getPriority())); + } - if (!mChannelp) - { - // Ugh, we don't have any free channels. - // Now we have to reprioritize. - // For now, just don't play the sound. - //LL_WARNS() << "Aborting, no free channels" << LL_ENDL; - return false; - } + if (!mChannelp) + { + // Ugh, we don't have any free channels. + // Now we have to reprioritize. + // For now, just don't play the sound. + //LL_WARNS() << "Aborting, no free channels" << LL_ENDL; + return false; + } - mChannelp->setSource(this); - return true; + mChannelp->setSource(this); + return true; } void LLAudioSource::stop() @@ -1390,249 +1390,249 @@ void LLAudioSource::stop() bool LLAudioSource::play(const LLUUID &audio_uuid) { - // Special abuse of play(); don't play a sound, but kill it. - if (audio_uuid.isNull()) - { - if (getChannel()) - { - getChannel()->setSource(NULL); - setChannel(NULL); - if (!isMuted()) - { - mCurrentDatap = NULL; - } - } - return false; - } - - // Reset our age timeout if someone attempts to play the source. - mAgeTimer.reset(); - - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return false; - } - - LLAudioData *adp = gAudiop->getAudioData(audio_uuid); - addAudioData(adp); - - if (isMuted()) - { - return false; - } - - bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); - if (!has_buffer) - { - // Don't bother trying to set up a channel or anything, we don't have an audio buffer. - return false; - } - - if (!setupChannel()) - { - return false; - } - - if (isSyncSlave()) - { - // A sync slave, it doesn't start playing until it's synced up with the master. - // Flag this channel as waiting for sync, and return true. - getChannel()->setWaiting(true); - return true; - } - - getChannel()->play(); - return true; + // Special abuse of play(); don't play a sound, but kill it. + if (audio_uuid.isNull()) + { + if (getChannel()) + { + getChannel()->setSource(NULL); + setChannel(NULL); + if (!isMuted()) + { + mCurrentDatap = NULL; + } + } + return false; + } + + // Reset our age timeout if someone attempts to play the source. + mAgeTimer.reset(); + + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return false; + } + + LLAudioData *adp = gAudiop->getAudioData(audio_uuid); + addAudioData(adp); + + if (isMuted()) + { + return false; + } + + bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); + if (!has_buffer) + { + // Don't bother trying to set up a channel or anything, we don't have an audio buffer. + return false; + } + + if (!setupChannel()) + { + return false; + } + + if (isSyncSlave()) + { + // A sync slave, it doesn't start playing until it's synced up with the master. + // Flag this channel as waiting for sync, and return true. + getChannel()->setWaiting(true); + return true; + } + + getChannel()->play(); + return true; } bool LLAudioSource::isDone() const { - if(mCorrupted) - { - return true ; - } - - const F32 MAX_AGE = 60.f; - const F32 MAX_UNPLAYED_AGE = 15.f; - const F32 MAX_MUTED_AGE = 11.f; - - if (isLoop()) - { - // Looped sources never die on their own. - return false; - } - - if (hasPendingPreloads()) - { - return false; - } - - if (mQueuedDatap) - { - // Don't kill this sound if we've got something queued up to play. - return false; - } - - F32 elapsed = mAgeTimer.getElapsedTimeF32(); - - // This is a single-play source - if (!mChannelp) - { - if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce) - { - // We don't have a channel assigned, and it's been - // over 15 seconds since we tried to play it. Don't bother. - //LL_INFOS() << "No channel assigned, source is done" << LL_ENDL; - return true; - } - else - { - return false; - } - } - - if (mChannelp->isPlaying()) - { - if (elapsed > MAX_AGE) - { - // Arbitarily cut off non-looped sounds when they're old. - return true; - } - else - { - // Sound is still playing and we haven't timed out, don't kill it. - return false; - } - } - - if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) - { - // The sound isn't playing back after 15 seconds or we're already done playing it, kill it. - return true; - } - - return false; + if(mCorrupted) + { + return true ; + } + + const F32 MAX_AGE = 60.f; + const F32 MAX_UNPLAYED_AGE = 15.f; + const F32 MAX_MUTED_AGE = 11.f; + + if (isLoop()) + { + // Looped sources never die on their own. + return false; + } + + if (hasPendingPreloads()) + { + return false; + } + + if (mQueuedDatap) + { + // Don't kill this sound if we've got something queued up to play. + return false; + } + + F32 elapsed = mAgeTimer.getElapsedTimeF32(); + + // This is a single-play source + if (!mChannelp) + { + if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce) + { + // We don't have a channel assigned, and it's been + // over 15 seconds since we tried to play it. Don't bother. + //LL_INFOS() << "No channel assigned, source is done" << LL_ENDL; + return true; + } + else + { + return false; + } + } + + if (mChannelp->isPlaying()) + { + if (elapsed > MAX_AGE) + { + // Arbitarily cut off non-looped sounds when they're old. + return true; + } + else + { + // Sound is still playing and we haven't timed out, don't kill it. + return false; + } + } + + if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) + { + // The sound isn't playing back after 15 seconds or we're already done playing it, kill it. + return true; + } + + return false; } void LLAudioSource::addAudioData(LLAudioData *adp, const bool set_current) { - // Only handle a single piece of audio data associated with a source right now, - // until I implement prefetch. - - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return; - } - - if (set_current) - { - if (!mCurrentDatap) - { - mCurrentDatap = adp; - if (mChannelp) - { - mChannelp->updateBuffer(); - mChannelp->play(); - } - - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - return; - } - else if (mQueueSounds) - { - // If we have current data, and we're queuing, put - // the object onto the queue. - if (mQueuedDatap) - { - // We only queue one sound at a time, and it's a FIFO. - // Don't put it onto the queue. - return; - } - - if (adp == mCurrentDatap && isLoop()) - { - // No point in queueing the same sound if - // we're looping. - return; - } - mQueuedDatap = adp; - - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - } - else - { - if (mCurrentDatap != adp) - { - // Right now, if we're currently playing this sound in a channel, we - // update the buffer that the channel's associated with - // and play it. This may not be the correct behavior. - mCurrentDatap = adp; - if (mChannelp) - { - mChannelp->updateBuffer(); - mChannelp->play(); - } - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - } - } - } - else - { - // Add it to the preload list. - mPreloadMap[adp->getID()] = adp; - gAudiop->startNextTransfer(); - } + // Only handle a single piece of audio data associated with a source right now, + // until I implement prefetch. + + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } + + if (set_current) + { + if (!mCurrentDatap) + { + mCurrentDatap = adp; + if (mChannelp) + { + mChannelp->updateBuffer(); + mChannelp->play(); + } + + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + return; + } + else if (mQueueSounds) + { + // If we have current data, and we're queuing, put + // the object onto the queue. + if (mQueuedDatap) + { + // We only queue one sound at a time, and it's a FIFO. + // Don't put it onto the queue. + return; + } + + if (adp == mCurrentDatap && isLoop()) + { + // No point in queueing the same sound if + // we're looping. + return; + } + mQueuedDatap = adp; + + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + } + else + { + if (mCurrentDatap != adp) + { + // Right now, if we're currently playing this sound in a channel, we + // update the buffer that the channel's associated with + // and play it. This may not be the correct behavior. + mCurrentDatap = adp; + if (mChannelp) + { + mChannelp->updateBuffer(); + mChannelp->play(); + } + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + } + } + } + else + { + // Add it to the preload list. + mPreloadMap[adp->getID()] = adp; + gAudiop->startNextTransfer(); + } } bool LLAudioSource::hasPendingPreloads() const { - // Check to see if we've got any preloads on deck for this source - for (const data_map::value_type& preload_pair : mPreloadMap) - { - LLAudioData *adp = preload_pair.second; - // note: a bad UUID will forever be !hasDecodedData() + // Check to see if we've got any preloads on deck for this source + for (const data_map::value_type& preload_pair : mPreloadMap) + { + LLAudioData *adp = preload_pair.second; + // note: a bad UUID will forever be !hasDecodedData() // but also hasDecodeFailed(), hence the check for hasDecodeFailed() - if (!adp) - { - continue; - } + if (!adp) + { + continue; + } if (!adp->hasDecodedData() && !adp->hasDecodeFailed()) - { - // This source is still waiting for a preload - return true; - } - } + { + // This source is still waiting for a preload + return true; + } + } - return false; + return false; } LLAudioData * LLAudioSource::getCurrentData() { - return mCurrentDatap; + return mCurrentDatap; } LLAudioData * LLAudioSource::getQueuedData() { - return mQueuedDatap; + return mQueuedDatap; } LLAudioBuffer * LLAudioSource::getCurrentBuffer() { - if (!mCurrentDatap) - { - return NULL; - } + if (!mCurrentDatap) + { + return NULL; + } - return mCurrentDatap->getBuffer(); + return mCurrentDatap->getBuffer(); } @@ -1644,106 +1644,106 @@ LLAudioBuffer * LLAudioSource::getCurrentBuffer() LLAudioChannel::LLAudioChannel() : - mCurrentSourcep(NULL), - mCurrentBufferp(NULL), - mLoopedThisFrame(false), - mWaiting(false), - mSecondaryGain(1.0f) + mCurrentSourcep(NULL), + mCurrentBufferp(NULL), + mLoopedThisFrame(false), + mWaiting(false), + mSecondaryGain(1.0f) { } LLAudioChannel::~LLAudioChannel() { - // Need to disconnect any sources which are using this channel. - //LL_INFOS() << "Cleaning up audio channel" << LL_ENDL; - if (mCurrentSourcep) - { - mCurrentSourcep->setChannel(NULL); - } - mCurrentBufferp = NULL; + // Need to disconnect any sources which are using this channel. + //LL_INFOS() << "Cleaning up audio channel" << LL_ENDL; + if (mCurrentSourcep) + { + mCurrentSourcep->setChannel(NULL); + } + mCurrentBufferp = NULL; } void LLAudioChannel::setSource(LLAudioSource *sourcep) { - //LL_INFOS() << this << ": setSource(" << sourcep << ")" << LL_ENDL; + //LL_INFOS() << this << ": setSource(" << sourcep << ")" << LL_ENDL; - if (!sourcep) - { - // Clearing the source for this channel, don't need to do anything. - //LL_INFOS() << "Clearing source for channel" << LL_ENDL; - cleanup(); - mCurrentSourcep = NULL; - mWaiting = false; - } - else - { - LL_DEBUGS("AudioEngine") << "( id: " << sourcep->getID() << ")" << LL_ENDL; + if (!sourcep) + { + // Clearing the source for this channel, don't need to do anything. + //LL_INFOS() << "Clearing source for channel" << LL_ENDL; + cleanup(); + mCurrentSourcep = NULL; + mWaiting = false; + } + else + { + LL_DEBUGS("AudioEngine") << "( id: " << sourcep->getID() << ")" << LL_ENDL; - if (sourcep == mCurrentSourcep) - { - // Don't reallocate the channel, this will make FMOD goofy. - //LL_INFOS() << "Calling setSource with same source!" << LL_ENDL; - } + if (sourcep == mCurrentSourcep) + { + // Don't reallocate the channel, this will make FMOD goofy. + //LL_INFOS() << "Calling setSource with same source!" << LL_ENDL; + } - mCurrentSourcep = sourcep; + mCurrentSourcep = sourcep; - updateBuffer(); - update3DPosition(); - } + updateBuffer(); + update3DPosition(); + } } bool LLAudioChannel::updateBuffer() { - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return false; - } + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return false; + } - if (!mCurrentSourcep) - { - // This channel isn't associated with any source, nothing - // to be updated - return false; - } + if (!mCurrentSourcep) + { + // This channel isn't associated with any source, nothing + // to be updated + return false; + } - // Initialize the channel's gain setting for this sound. - setSecondaryGain(gAudiop->getSecondaryGain(mCurrentSourcep->getType())); + // Initialize the channel's gain setting for this sound. + setSecondaryGain(gAudiop->getSecondaryGain(mCurrentSourcep->getType())); - LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer(); - if (bufferp == mCurrentBufferp) - { - if (bufferp) - { - // The source hasn't changed what buffer it's playing - bufferp->mLastUseTimer.reset(); - bufferp->mInUse = true; - } - return false; - } + LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer(); + if (bufferp == mCurrentBufferp) + { + if (bufferp) + { + // The source hasn't changed what buffer it's playing + bufferp->mLastUseTimer.reset(); + bufferp->mInUse = true; + } + return false; + } - // - // The source changed what buffer it's playing. We need to clean up - // the existing channel - // - cleanup(); + // + // The source changed what buffer it's playing. We need to clean up + // the existing channel + // + cleanup(); - mCurrentBufferp = bufferp; - if (bufferp) - { - bufferp->mLastUseTimer.reset(); - bufferp->mInUse = true; - } + mCurrentBufferp = bufferp; + if (bufferp) + { + bufferp->mLastUseTimer.reset(); + bufferp->mInUse = true; + } - if (!mCurrentBufferp) - { - // There's no new buffer to be played, so we just abort. - return false; - } + if (!mCurrentBufferp) + { + // There's no new buffer to be played, so we just abort. + return false; + } - return true; + return true; } @@ -1755,82 +1755,92 @@ bool LLAudioChannel::updateBuffer() LLAudioData::LLAudioData(const LLUUID &uuid) : - mID(uuid), - mBufferp(NULL), - mHasLocalData(false), - mHasDecodedData(false), - mHasCompletedDecode(false), + mID(uuid), + mBufferp(NULL), + mHasLocalData(false), + mHasDecodedData(false), + mHasCompletedDecode(false), mHasDecodeFailed(false), mHasWAVLoadFailed(false) { - if (uuid.isNull()) - { - // This is a null sound. - return; - } - - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return; - } - - if (gAudiop->hasDecodedFile(uuid)) - { - // Already have a decoded version, don't need to decode it. - setHasLocalData(true); - setHasDecodedData(true); - setHasCompletedDecode(true); - } - else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) - { - setHasLocalData(true); - } + if (uuid.isNull()) + { + // This is a null sound. + return; + } + + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } + + if (gAudiop->hasDecodedFile(uuid)) + { + // Already have a decoded version, don't need to decode it. + setHasLocalData(true); + setHasDecodedData(true); + setHasCompletedDecode(true); + } + else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + { + setHasLocalData(true); + } } //return false when the audio file is corrupted. bool LLAudioData::load() { - // For now, just assume we're going to use one buffer per audiodata. - if (mBufferp) - { - // We already have this sound in a buffer, don't do anything. - LL_INFOS() << "Already have a buffer for this sound, don't bother loading!" << LL_ENDL; + // For now, just assume we're going to use one buffer per audiodata. + if (mBufferp) + { + // We already have this sound in a buffer, don't do anything. + LL_INFOS() << "Already have a buffer for this sound, don't bother loading!" << LL_ENDL; mHasWAVLoadFailed = false; - return true; - } + return true; + } - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; mHasWAVLoadFailed = true; - return false; - } - - mBufferp = gAudiop->getFreeBuffer(); - if (!mBufferp) - { - // No free buffers, abort. - LL_INFOS() << "Not able to allocate a new audio buffer, aborting." << LL_ENDL; + return false; + } + + mBufferp = gAudiop->getFreeBuffer(); + if (!mBufferp) + { + // No free buffers, abort. + LL_INFOS() << "Not able to allocate a new audio buffer, aborting." << LL_ENDL; // *TODO: Mark this failure differently so the audio engine could retry loading this buffer in the future mHasWAVLoadFailed = true; - return true; - } + return true; + } - std::string uuid_str; - std::string wav_path; - mID.toString(uuid_str); - wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf"; + std::string uuid_str; + std::string wav_path; + mID.toString(uuid_str); + wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf"; mHasWAVLoadFailed = !mBufferp->loadWAV(wav_path); if (mHasWAVLoadFailed) - { - // Hrm. Right now, let's unset the buffer, since it's empty. - gAudiop->cleanupBuffer(mBufferp); - mBufferp = NULL; - - return false; - } - mBufferp->mAudioDatap = this; - return true; + { + // Hrm. Right now, let's unset the buffer, since it's empty. + gAudiop->cleanupBuffer(mBufferp); + mBufferp = nullptr; + + if (!gDirUtilp->fileExists(wav_path)) + { + mHasLocalData = false; + mHasDecodedData = false; + mHasCompletedDecode = false; + mHasDecodeFailed = false; + mHasWAVLoadFailed = false; + gAudiop->preloadSound(mID); + } + + return false; + } + mBufferp->mAudioDatap = this; + return true; } diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index c045d18c42..a9a229c0a5 100755 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -1,25 +1,25 @@ -/** +/** * @file audioengine.h * @brief Definition of LLAudioEngine base class abstracting the audio support * * $LicenseInfo:firstyear=2000&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$ */ @@ -62,186 +62,186 @@ struct SoundData; // // LLAudioEngine definition // -class LLAudioEngine +class LLAudioEngine { - friend class LLAudioChannelOpenAL; // bleh. channel needs some listener methods. - + friend class LLAudioChannelOpenAL; // bleh. channel needs some listener methods. + public: - enum LLAudioType - { - AUDIO_TYPE_NONE = 0, - AUDIO_TYPE_SFX = 1, - AUDIO_TYPE_UI = 2, - AUDIO_TYPE_AMBIENT = 3, - AUDIO_TYPE_COUNT = 4 // last - }; - - enum LLAudioPlayState - { - // isInternetStreamPlaying() returns an *S32*, with - // 0 = stopped, 1 = playing, 2 = paused. - AUDIO_STOPPED = 0, - AUDIO_PLAYING = 1, - AUDIO_PAUSED = 2 - }; - - LLAudioEngine(); - virtual ~LLAudioEngine(); - - // initialization/startup/shutdown - virtual bool init(void *userdata, const std::string &app_title); - virtual std::string getDriverName(bool verbose) = 0; - virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0; - virtual void shutdown(); - - // Used by the mechanics of the engine - //virtual void processQueue(const LLUUID &sound_guid); - virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at); - virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0; - virtual void idle(); - virtual void updateChannels(); - - // - // "End user" functionality - // - virtual bool isWindEnabled(); - virtual void enableWind(bool state_b); - - // Use these for temporarily muting the audio system. - // Does not change buffers, initialization, etc. but - // stops playing new sounds. - void setMuted(bool muted); - bool getMuted() const { return mMuted; } + enum LLAudioType + { + AUDIO_TYPE_NONE = 0, + AUDIO_TYPE_SFX = 1, + AUDIO_TYPE_UI = 2, + AUDIO_TYPE_AMBIENT = 3, + AUDIO_TYPE_COUNT = 4 // last + }; + + enum LLAudioPlayState + { + // isInternetStreamPlaying() returns an *S32*, with + // 0 = stopped, 1 = playing, 2 = paused. + AUDIO_STOPPED = 0, + AUDIO_PLAYING = 1, + AUDIO_PAUSED = 2 + }; + + LLAudioEngine(); + virtual ~LLAudioEngine(); + + // initialization/startup/shutdown + virtual bool init(void *userdata, const std::string &app_title); + virtual std::string getDriverName(bool verbose) = 0; + virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0; + virtual void shutdown(); + + // Used by the mechanics of the engine + //virtual void processQueue(const LLUUID &sound_guid); + virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at); + virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0; + virtual void idle(); + virtual void updateChannels(); + + // + // "End user" functionality + // + virtual bool isWindEnabled(); + virtual void enableWind(bool state_b); + + // Use these for temporarily muting the audio system. + // Does not change buffers, initialization, etc. but + // stops playing new sounds. + void setMuted(bool muted); + bool getMuted() const { return mMuted; } #ifdef USE_PLUGIN_MEDIA - LLPluginClassMedia* initializeMedia(const std::string& media_type); + LLPluginClassMedia* initializeMedia(const std::string& media_type); #endif - F32 getMasterGain(); - void setMasterGain(F32 gain); + F32 getMasterGain(); + void setMasterGain(F32 gain); + + F32 getSecondaryGain(S32 type); + void setSecondaryGain(S32 type, F32 gain); - F32 getSecondaryGain(S32 type); - void setSecondaryGain(S32 type, F32 gain); + F32 getInternetStreamGain(); - F32 getInternetStreamGain(); + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + virtual void setMaxWindGain(F32 gain); - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - virtual void setMaxWindGain(F32 gain); + // Methods actually related to setting up and removing sounds + // Owner ID is the owner of the object making the request + void triggerSound(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, + const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, + const LLVector3d &pos_global = LLVector3d::zero); + void triggerSound(SoundData& soundData); - // Methods actually related to setting up and removing sounds - // Owner ID is the owner of the object making the request - void triggerSound(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, - const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, - const LLVector3d &pos_global = LLVector3d::zero); - void triggerSound(SoundData& soundData); + bool preloadSound(const LLUUID &id); - bool preloadSound(const LLUUID &id); + void addAudioSource(LLAudioSource *asp); + void cleanupAudioSource(LLAudioSource *asp); - void addAudioSource(LLAudioSource *asp); - void cleanupAudioSource(LLAudioSource *asp); + LLAudioSource *findAudioSource(const LLUUID &source_id); + LLAudioData *getAudioData(const LLUUID &audio_uuid); - LLAudioSource *findAudioSource(const LLUUID &source_id); - LLAudioData *getAudioData(const LLUUID &audio_uuid); + // Internet stream implementation manipulation + LLStreamingAudioInterface *getStreamingAudioImpl(); + void setStreamingAudioImpl(LLStreamingAudioInterface *impl); + // Internet stream methods - these will call down into the *mStreamingAudioImpl if it exists + void startInternetStream(const std::string& url); + void stopInternetStream(); + void pauseInternetStream(S32 pause); + void updateInternetStream(); // expected to be called often + LLAudioPlayState isInternetStreamPlaying(); + // use a value from 0.0 to 1.0, inclusive + void setInternetStreamGain(F32 vol); + std::string getInternetStreamURL(); - // Internet stream implementation manipulation - LLStreamingAudioInterface *getStreamingAudioImpl(); - void setStreamingAudioImpl(LLStreamingAudioInterface *impl); - // Internet stream methods - these will call down into the *mStreamingAudioImpl if it exists - void startInternetStream(const std::string& url); - void stopInternetStream(); - void pauseInternetStream(S32 pause); - void updateInternetStream(); // expected to be called often - LLAudioPlayState isInternetStreamPlaying(); - // use a value from 0.0 to 1.0, inclusive - void setInternetStreamGain(F32 vol); - std::string getInternetStreamURL(); - - // For debugging usage - virtual LLVector3 getListenerPos(); + // For debugging usage + virtual LLVector3 getListenerPos(); - LLAudioBuffer *getFreeBuffer(); // Get a free buffer, or flush an existing one if you have to. - LLAudioChannel *getFreeChannel(const F32 priority); // Get a free channel or flush an existing one if your priority is higher - void cleanupBuffer(LLAudioBuffer *bufferp); + LLAudioBuffer *getFreeBuffer(); // Get a free buffer, or flush an existing one if you have to. + LLAudioChannel *getFreeChannel(const F32 priority); // Get a free channel or flush an existing one if your priority is higher + void cleanupBuffer(LLAudioBuffer *bufferp); - bool hasDecodedFile(const LLUUID &uuid); - bool hasLocalFile(const LLUUID &uuid); + bool hasDecodedFile(const LLUUID &uuid); + bool hasLocalFile(const LLUUID &uuid); - bool updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid = LLUUID::null); + bool updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid = LLUUID::null); - // Asset callback when we're retrieved a sound from the asset server. - void startNextTransfer(); - static void assetCallback(const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status); + // Asset callback when we're retrieved a sound from the asset server. + void startNextTransfer(); + static void assetCallback(const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status); - friend class LLPipeline; // For debugging + friend class LLPipeline; // For debugging public: - F32 mMaxWindGain; // Hack. Public to set before fade in? + F32 mMaxWindGain; // Hack. Public to set before fade in? protected: - virtual LLAudioBuffer *createBuffer() = 0; - virtual LLAudioChannel *createChannel() = 0; + virtual LLAudioBuffer *createBuffer() = 0; + virtual LLAudioChannel *createChannel() = 0; - virtual bool initWind() = 0; - virtual void cleanupWind() = 0; - virtual void setInternalGain(F32 gain) = 0; + virtual bool initWind() = 0; + virtual void cleanupWind() = 0; + virtual void setInternalGain(F32 gain) = 0; - void commitDeferredChanges(); + void commitDeferredChanges(); - virtual void allocateListener() = 0; + virtual void allocateListener() = 0; - // listener methods - virtual void setListenerPos(LLVector3 vec); - virtual void setListenerVelocity(LLVector3 vec); - virtual void orientListener(LLVector3 up, LLVector3 at); - virtual void translateListener(LLVector3 vec); + // listener methods + virtual void setListenerPos(LLVector3 vec); + virtual void setListenerVelocity(LLVector3 vec); + virtual void orientListener(LLVector3 up, LLVector3 at); + virtual void translateListener(LLVector3 vec); - F64 mapWindVecToGain(LLVector3 wind_vec); - F64 mapWindVecToPitch(LLVector3 wind_vec); - F64 mapWindVecToPan(LLVector3 wind_vec); + F64 mapWindVecToGain(LLVector3 wind_vec); + F64 mapWindVecToPitch(LLVector3 wind_vec); + F64 mapWindVecToPan(LLVector3 wind_vec); protected: - LLListener *mListenerp; + LLListener *mListenerp; - bool mMuted; - void* mUserData; + bool mMuted; + void* mUserData; - S32 mLastStatus; - - bool mEnableWind; + S32 mLastStatus; - LLUUID mCurrentTransfer; // Audio file currently being transferred by the system - LLFrameTimer mCurrentTransferTimer; + bool mEnableWind; - // A list of all audio sources that are known to the viewer at this time. - // This is most likely a superset of the ones that we actually have audio - // data for, or are playing back. - typedef std::map<LLUUID, LLAudioSource *> source_map; - typedef std::map<LLUUID, LLAudioData *> data_map; + LLUUID mCurrentTransfer; // Audio file currently being transferred by the system + LLFrameTimer mCurrentTransferTimer; - source_map mAllSources; - data_map mAllData; + // A list of all audio sources that are known to the viewer at this time. + // This is most likely a superset of the ones that we actually have audio + // data for, or are playing back. + typedef std::map<LLUUID, LLAudioSource *> source_map; + typedef std::map<LLUUID, LLAudioData *> data_map; + + source_map mAllSources; + data_map mAllData; std::array<LLAudioChannel*, LL_MAX_AUDIO_CHANNELS> mChannels; - // Buffers needs to change into a different data structure, as the number of buffers - // that we have active should be limited by RAM usage, not count. + // Buffers needs to change into a different data structure, as the number of buffers + // that we have active should be limited by RAM usage, not count. std::array<LLAudioBuffer*, LL_MAX_AUDIO_BUFFERS> mBuffers; - - F32 mMasterGain; - F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true. - F32 mSecondaryGain[AUDIO_TYPE_COUNT]; - F32 mNextWindUpdate; + F32 mMasterGain; + F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true. + F32 mSecondaryGain[AUDIO_TYPE_COUNT]; + + F32 mNextWindUpdate; - LLFrameTimer mWindUpdateTimer; + LLFrameTimer mWindUpdateTimer; private: - void setDefaults(); - LLStreamingAudioInterface *mStreamingAudioImpl; + void setDefaults(); + LLStreamingAudioInterface *mStreamingAudioImpl; }; @@ -255,56 +255,56 @@ private: class LLAudioSource { public: - // owner_id is the id of the agent responsible for making this sound - // play, for example, the owner of the object currently playing it - LLAudioSource(const LLUUID &id, const LLUUID& owner_id, const F32 gain, const S32 type = LLAudioEngine::AUDIO_TYPE_NONE); - virtual ~LLAudioSource(); + // owner_id is the id of the agent responsible for making this sound + // play, for example, the owner of the object currently playing it + LLAudioSource(const LLUUID &id, const LLUUID& owner_id, const F32 gain, const S32 type = LLAudioEngine::AUDIO_TYPE_NONE); + virtual ~LLAudioSource(); - virtual void update(); // Update this audio source - void updatePriority(); + virtual void update(); // Update this audio source + void updatePriority(); - void preload(const LLUUID &audio_id); // Only used for preloading UI sounds, now. + void preload(const LLUUID &audio_id); // Only used for preloading UI sounds, now. - void addAudioData(LLAudioData *adp, bool set_current = TRUE); + void addAudioData(LLAudioData *adp, bool set_current = true); - void setForcedPriority(const bool ambient) { mForcedPriority = ambient; } - bool isForcedPriority() const { return mForcedPriority; } + void setForcedPriority(const bool ambient) { mForcedPriority = ambient; } + bool isForcedPriority() const { return mForcedPriority; } - void setLoop(const bool loop) { mLoop = loop; } - bool isLoop() const { return mLoop; } + void setLoop(const bool loop) { mLoop = loop; } + bool isLoop() const { return mLoop; } - void setSyncMaster(const bool master) { mSyncMaster = master; } - bool isSyncMaster() const { return mSyncMaster; } + void setSyncMaster(const bool master) { mSyncMaster = master; } + bool isSyncMaster() const { return mSyncMaster; } - void setSyncSlave(const bool slave) { mSyncSlave = slave; } - bool isSyncSlave() const { return mSyncSlave; } + void setSyncSlave(const bool slave) { mSyncSlave = slave; } + bool isSyncSlave() const { return mSyncSlave; } - void setQueueSounds(const bool queue) { mQueueSounds = queue; } - bool isQueueSounds() const { return mQueueSounds; } + void setQueueSounds(const bool queue) { mQueueSounds = queue; } + bool isQueueSounds() const { return mQueueSounds; } - void setPlayedOnce(const bool played_once) { mPlayedOnce = played_once; } + void setPlayedOnce(const bool played_once) { mPlayedOnce = played_once; } - void setType(S32 type) { mType = type; } - S32 getType() { return mType; } + void setType(S32 type) { mType = type; } + S32 getType() { return mType; } - void setPositionGlobal(const LLVector3d &position_global) { mPositionGlobal = position_global; } - LLVector3d getPositionGlobal() const { return mPositionGlobal; } - LLVector3 getVelocity() const { return mVelocity; } - F32 getPriority() const { return mPriority; } + void setPositionGlobal(const LLVector3d &position_global) { mPositionGlobal = position_global; } + LLVector3d getPositionGlobal() const { return mPositionGlobal; } + LLVector3 getVelocity() const { return mVelocity; } + F32 getPriority() const { return mPriority; } - // Gain should always be clamped between 0 and 1. - F32 getGain() const { return mGain; } - virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); } + // Gain should always be clamped between 0 and 1. + F32 getGain() const { return mGain; } + virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); } - const LLUUID &getID() const { return mID; } - bool isDone() const; - bool isMuted() const { return mSourceMuted; } + const LLUUID &getID() const { return mID; } + bool isDone() const; + bool isMuted() const { return mSourceMuted; } - LLAudioData *getCurrentData(); - LLAudioData *getQueuedData(); - LLAudioBuffer *getCurrentBuffer(); + LLAudioData *getCurrentData(); + LLAudioData *getQueuedData(); + LLAudioBuffer *getCurrentBuffer(); - bool setupChannel(); + bool setupChannel(); // Stop the audio source, reset audio id even if muted void stop(); @@ -313,40 +313,40 @@ public: // takes mute into account to preserve previous id if nessesary bool play(const LLUUID &audio_id); - bool hasPendingPreloads() const; // Has preloads that haven't been done yet + bool hasPendingPreloads() const; // Has preloads that haven't been done yet - friend class LLAudioEngine; - friend class LLAudioChannel; + friend class LLAudioEngine; + friend class LLAudioChannel; protected: - void setChannel(LLAudioChannel *channelp); - LLAudioChannel *getChannel() const { return mChannelp; } + void setChannel(LLAudioChannel *channelp); + LLAudioChannel *getChannel() const { return mChannelp; } protected: - LLUUID mID; // The ID of the source is that of the object if it's attached to an object. - LLUUID mOwnerID; // owner of the object playing the sound - F32 mPriority; - F32 mGain; - bool mSourceMuted; - bool mForcedPriority; // ignore mute, set high priority, researved for sound preview and UI - bool mLoop; - bool mSyncMaster; - bool mSyncSlave; - bool mQueueSounds; - bool mPlayedOnce; - bool mCorrupted; - S32 mType; - LLVector3d mPositionGlobal; - LLVector3 mVelocity; - - //LLAudioSource *mSyncMasterp; // If we're a slave, the source that we're synced to. - LLAudioChannel *mChannelp; // If we're currently playing back, this is the channel that we're assigned to. - LLAudioData *mCurrentDatap; - LLAudioData *mQueuedDatap; - - typedef std::map<LLUUID, LLAudioData *> data_map; - data_map mPreloadMap; - - LLFrameTimer mAgeTimer; + LLUUID mID; // The ID of the source is that of the object if it's attached to an object. + LLUUID mOwnerID; // owner of the object playing the sound + F32 mPriority; + F32 mGain; + bool mSourceMuted; + bool mForcedPriority; // ignore mute, set high priority, researved for sound preview and UI + bool mLoop; + bool mSyncMaster; + bool mSyncSlave; + bool mQueueSounds; + bool mPlayedOnce; + bool mCorrupted; + S32 mType; + LLVector3d mPositionGlobal; + LLVector3 mVelocity; + + //LLAudioSource *mSyncMasterp; // If we're a slave, the source that we're synced to. + LLAudioChannel *mChannelp; // If we're currently playing back, this is the channel that we're assigned to. + LLAudioData *mCurrentDatap; + LLAudioData *mQueuedDatap; + + typedef std::map<LLUUID, LLAudioData *> data_map; + data_map mPreloadMap; + + LLFrameTimer mAgeTimer; }; @@ -404,34 +404,34 @@ class LLAudioData class LLAudioChannel { public: - LLAudioChannel(); - virtual ~LLAudioChannel(); + LLAudioChannel(); + virtual ~LLAudioChannel(); - virtual void setSource(LLAudioSource *sourcep); - LLAudioSource *getSource() const { return mCurrentSourcep; } + virtual void setSource(LLAudioSource *sourcep); + LLAudioSource *getSource() const { return mCurrentSourcep; } - void setSecondaryGain(F32 gain) { mSecondaryGain = gain; } - F32 getSecondaryGain() { return mSecondaryGain; } + void setSecondaryGain(F32 gain) { mSecondaryGain = gain; } + F32 getSecondaryGain() { return mSecondaryGain; } - friend class LLAudioEngine; - friend class LLAudioSource; + friend class LLAudioEngine; + friend class LLAudioSource; protected: - virtual void play() = 0; - virtual void playSynced(LLAudioChannel *channelp) = 0; - virtual void cleanup() = 0; - virtual bool isPlaying() = 0; - void setWaiting(const bool waiting) { mWaiting = waiting; } - bool isWaiting() const { return mWaiting; } - - virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary. - virtual void update3DPosition() = 0; - virtual void updateLoop() = 0; // Update your loop/completion status, for use by queueing/syncing. + virtual void play() = 0; + virtual void playSynced(LLAudioChannel *channelp) = 0; + virtual void cleanup() = 0; + virtual bool isPlaying() = 0; + void setWaiting(const bool waiting) { mWaiting = waiting; } + bool isWaiting() const { return mWaiting; } + + virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary. + virtual void update3DPosition() = 0; + virtual void updateLoop() = 0; // Update your loop/completion status, for use by queueing/syncing. protected: - LLAudioSource *mCurrentSourcep; - LLAudioBuffer *mCurrentBufferp; - bool mLoopedThisFrame; - bool mWaiting; // Waiting for sync. - F32 mSecondaryGain; + LLAudioSource *mCurrentSourcep; + LLAudioBuffer *mCurrentBufferp; + bool mLoopedThisFrame; + bool mWaiting; // Waiting for sync. + F32 mSecondaryGain; }; @@ -445,39 +445,39 @@ protected: class LLAudioBuffer { public: - virtual ~LLAudioBuffer() {}; - virtual bool loadWAV(const std::string& filename) = 0; - virtual U32 getLength() = 0; + virtual ~LLAudioBuffer() {}; + virtual bool loadWAV(const std::string& filename) = 0; + virtual U32 getLength() = 0; - friend class LLAudioEngine; - friend class LLAudioChannel; - friend class LLAudioData; + friend class LLAudioEngine; + friend class LLAudioChannel; + friend class LLAudioData; protected: - bool mInUse; - LLAudioData *mAudioDatap; - LLFrameTimer mLastUseTimer; + bool mInUse; + LLAudioData *mAudioDatap; + LLFrameTimer mLastUseTimer; }; struct SoundData { - LLUUID audio_uuid; - LLUUID owner_id; - F32 gain; - S32 type; - LLVector3d pos_global; - - SoundData(const LLUUID &audio_uuid, - const LLUUID& owner_id, - const F32 gain, - const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, - const LLVector3d &pos_global = LLVector3d::zero) : - audio_uuid(audio_uuid), - owner_id(owner_id), - gain(gain), - type(type), - pos_global(pos_global) - { - } + LLUUID audio_uuid; + LLUUID owner_id; + F32 gain; + S32 type; + LLVector3d pos_global; + + SoundData(const LLUUID &audio_uuid, + const LLUUID& owner_id, + const F32 gain, + const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, + const LLVector3d &pos_global = LLVector3d::zero) : + audio_uuid(audio_uuid), + owner_id(owner_id), + gain(gain), + type(type), + pos_global(pos_global) + { + } }; diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp deleted file mode 100644 index c6313ea289..0000000000 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ /dev/null @@ -1,756 +0,0 @@ -/** - * @file audioengine_fmodstudio.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmodstudio.h" - -#include "llaudioengine_fmodstudio.h" -#include "lllistener_fmodstudio.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmodstudio/fmod.hpp" -#include "fmodstudio/fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); - -FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler) -: mInited(false), - mWindGen(NULL), - mWindDSP(NULL), - mSystem(NULL), - mEnableProfiler(enable_profiler), - mWindDSPDesc(NULL) -{ -} - - -LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() -{ - // mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown() - // mSystem gets cleaned up at shutdown() -} - - -static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if (result == FMOD_OK) - return false; - LL_DEBUGS("FMOD") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - return true; -} - -bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title) -{ - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; - - result = FMOD::System_Create(&mSystem); - if (Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(userdata, app_title); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "FMOD Studio version mismatch, actual: " << version - << " expected:" << FMOD_VERSION << LL_ENDL; - } - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(LL_MAX_AUDIO_CHANNELS + 2); - Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); - - FMOD_ADVANCEDSETTINGS settings; - memset(&settings, 0, sizeof(settings)); - settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); - settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; - - result = mSystem->setAdvancedSettings(&settings); - Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); - - // FMOD_INIT_THREAD_UNSAFE Disables thread safety for API calls. - // Only use this if FMOD is being called from a single thread, and if Studio API is not being used. - U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; - if (mEnableProfiler) - { - fmod_flags |= FMOD_INIT_PROFILE_ENABLE; - } - -#if LL_LINUX - bool audio_ok = false; - - if (!audio_ok) - { - const char* env_string = getenv("LL_BAD_FMOD_PULSEAUDIO"); - if (NULL == env_string) - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - const char* env_string = getenv("LL_BAD_FMOD_ALSA"); - if (NULL == env_string) - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if (mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && - (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // We're interested in logging which output method we - // ended up with, for QA purposes. - FMOD_OUTPUTTYPE output_type; - mSystem->getOutput(&output_type); - switch (output_type) - { - case FMOD_OUTPUTTYPE_NOSOUND: - LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_PULSEAUDIO: - LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_ALSA: - LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - default: - LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; -#else // LL_LINUX - - // initialize the FMOD engine - // number of channel in this case looks to be identiacal to number of max simultaneously - // playing objects and we can set practically any number - result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0); - if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format")) - { - result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/); - if (Check_FMOD_Error(result, "Error setting sotware format. Can't init.")) - { - return false; - } - result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0); - } - if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) - { - // If it fails here and (result == FMOD_ERR_OUTPUT_CREATEBUFFER), - // we can retry with other settings - return false; - } -#endif - - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels; - unsigned int r_bufferlength; - char r_name[512]; - int latency = 100; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - if (r_samplerate != 0) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; - - return true; -} - - -std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if (!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMOD STUDIO"; -} - - -// create our favourite FMOD-native streaming audio implementation -LLStreamingAudioInterface *LLAudioEngine_FMODSTUDIO::createDefaultStreamingAudioImpl() const -{ - return new LLStreamingAudio_FMODSTUDIO(mSystem); -} - - -void LLAudioEngine_FMODSTUDIO::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); - if (!mListenerp) - { - LL_WARNS("FMOD") << "Listener creation failed" << LL_ENDL; - } -} - - -void LLAudioEngine_FMODSTUDIO::shutdown() -{ - stopInternetStream(); - - LL_INFOS("FMOD") << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; - if (mSystem) - { - mSystem->close(); - mSystem->release(); - } - LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() -{ - return new LLAudioBufferFMODSTUDIO(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() -{ - return new LLAudioChannelFMODSTUDIO(mSystem); -} - -bool LLAudioEngine_FMODSTUDIO::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSPDesc) - { - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); - } - - if (!mWindDSP) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; - mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads - if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) - return false; - - if (mWindGen) - delete mWindGen; - - int frequency = 44100; - - FMOD_SPEAKERMODE mode; - if (Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) - { - cleanupWind(); - return false; - } - - mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); - - if (Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData")) - { - cleanupWind(); - return false; - } - if (Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat")) - { - cleanupWind(); - return false; - } - } - - // *TODO: Should this guard against multiple plays? - if (Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) - { - cleanupWind(); - return false; - } - return true; -} - - -void LLAudioEngine_FMODSTUDIO::cleanupWind() -{ - if (mWindDSP) - { - FMOD::ChannelGroup* master_group = NULL; - if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") - && master_group) - { - master_group->removeDSP(mWindDSP); - } - mWindDSP->release(); - mWindDSP = NULL; - } - - delete mWindDSPDesc; - mWindDSPDesc = NULL; - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch, 2.5*(mapWindVecToGain(wind_vec) + 1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp(gain, 0.0f, 1.0f); - - FMOD::ChannelGroup* master_group = NULL; - if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::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()); - } -} - -// -// LLAudioChannelFMODSTUDIO implementation -// - -LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() -{ - cleanup(); -} - -bool LLAudioChannelFMODSTUDIO::updateBuffer() -{ - if (!mCurrentSourcep) - { - // This channel isn't associated with any source, nothing - // to be updated - return false; - } - - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentSourcep->getCurrentBuffer(); - - // Grab the FMOD sample associated with the buffer - FMOD::Sound *soundp = bufferp->getSound(); - if (!soundp) - { - // This is bad, there should ALWAYS be a sound associated with a legit - // buffer. - LL_ERRS() << "No FMOD sound!" << LL_ENDL; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - if (!mChannelp) - { - FMOD_RESULT result = getSystem()->playSound(soundp, NULL /*free channel?*/, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - // Setting up channel mChannelID - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - //FMOD_RESULT result; - - mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); - - mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); - /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) - { - S32 index; - mChannelp->getIndex(&index); - LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() - << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; - }*/ - } - - return true; -} - - -void LLAudioChannelFMODSTUDIO::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - if (mCurrentSourcep->isForcedPriority()) - { - // Prioritized UI and preview sounds don't need to do any positional updates. - set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); - Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); - } -} - - -void LLAudioChannelFMODSTUDIO::updateLoop() -{ - if (!mChannelp) - { - // May want to clear up the loop/sample counters. - return; - } - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos; - mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES); - - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODSTUDIO::cleanup() -{ - if (!mChannelp) - { - // Aborting cleanup with no channel handle. - return; - } - - //Cleaning up channel mChannelID - Check_FMOD_Error(mChannelp->stop(), "FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODSTUDIO::play() -{ - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } - - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); - - getSource()->setPlayedOnce(true); - - if (LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]); -} - - -void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp; - if (!(fmod_channelp->mChannelp && mChannelp)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - U32 cur_pos; - if (Check_FMOD_Error(mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) - return; - - cur_pos %= mCurrentBufferp->getLength(); - - // Try to match the position of our sync master - Check_FMOD_Error(mChannelp->setPosition(cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to set current position"); - - // Start us playing - play(); -} - - -bool LLAudioChannelFMODSTUDIO::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); - return !paused && playing; -} - - -// -// LLAudioChannelFMODSTUDIO implementation -// - - -LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() -{ - if (mSoundp) - { - mSoundp->release(); - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!gDirUtilp->fileExists(filename)) - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - // If there's already something loaded in this buffer, clean it up. - mSoundp->release(); - mSoundp = NULL; - } - - FMOD_MODE base_mode = FMOD_LOOP_NORMAL; - FMOD_CREATESOUNDEXINFO exinfo; - memset(&exinfo, 0, sizeof(exinfo)); - exinfo.cbsize = sizeof(exinfo); - exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. - // Load up the wav file into an fmod sample (since 1.05 fmod studio expects everything in UTF-8) - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); - - if (result != FMOD_OK) - { - // We failed to load the file for some reason. - LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMODSTUDIO::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - return length; -} - - -void LLAudioChannelFMODSTUDIO::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); - } -} - -// *NOTE: This is almost certainly being called on the mixer thread, -// not the main thread. May have implications for callees or audio -// engine shutdown. - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) -{ - // inbuffer = fmod's original mixbuffer. - // outbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - - LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen = NULL; - FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; - - thisdsp->getUserData((void **)&windgen); - - if (windgen) - { - windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); - } - - return FMOD_OK; -} diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h deleted file mode 100644 index 29e7bc6bf0..0000000000 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file audioengine_fmodstudio.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_AUDIOENGINE_FMODSTUDIO_H -#define LL_AUDIOENGINE_FMODSTUDIO_H - -#include "llaudioengine.h" -#include "llwindgen.h" - -//Stubs -class LLAudioStreamManagerFMODSTUDIO; -namespace FMOD -{ - class System; - class Channel; - class ChannelGroup; - class Sound; - class DSP; -} -typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; - -//Interfaces -class LLAudioEngine_FMODSTUDIO : public LLAudioEngine -{ -public: - LLAudioEngine_FMODSTUDIO(bool enable_profiler); - virtual ~LLAudioEngine_FMODSTUDIO(); - - // initialization/startup/shutdown - virtual bool init(void *user_data, const std::string &app_title); - virtual std::string getDriverName(bool verbose); - virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const; - virtual void allocateListener(); - - virtual void shutdown(); - - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); - - /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); - - typedef F32 MIXBUFFERFORMAT; - - FMOD::System *getSystem() const {return mSystem;} -protected: - /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. - /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. - - /*virtual*/ void setInternalGain(F32 gain); - - bool mInited; - - LLWindGen<MIXBUFFERFORMAT> *mWindGen; - - FMOD_DSP_DESCRIPTION *mWindDSPDesc; - FMOD::DSP *mWindDSP; - FMOD::System *mSystem; - bool mEnableProfiler; - -public: - static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; -}; - - -class LLAudioChannelFMODSTUDIO : public LLAudioChannel -{ -public: - LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODSTUDIO(); - -protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); - - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); - - void set3DMode(bool use3d); -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Channel *mChannelp; - S32 mLastSamplePos; -}; - - -class LLAudioBufferFMODSTUDIO : public LLAudioBuffer -{ -public: - LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODSTUDIO(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODSTUDIO; -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Sound *getSound() const{ return mSoundp; } - FMOD::Sound *mSoundp; -}; - - -#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index 0a79614424..755547bfaa 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -6,21 +6,21 @@ * $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$ */ @@ -35,14 +35,14 @@ const float LLAudioEngine_OpenAL::WIND_BUFFER_SIZE_SEC = 0.05f; LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() - : - mWindGen(NULL), - mWindBuf(NULL), - mWindBufFreq(0), - mWindBufSamples(0), - mWindBufBytes(0), - mWindSource(AL_NONE), - mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) + : + mWindGen(NULL), + mWindBuf(NULL), + mWindBufFreq(0), + mWindBufSamples(0), + mWindBufBytes(0), + mWindSource(AL_NONE), + mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) { } @@ -54,187 +54,198 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() // virtual bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title) { - mWindGen = NULL; - LLAudioEngine::init(userdata, app_title); + mWindGen = NULL; + LLAudioEngine::init(userdata, app_title); - if(!alutInit(NULL, NULL)) - { - LL_WARNS() << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; - return false; - } + if(!alutInit(NULL, NULL)) + { + LL_WARNS() << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; + return false; + } - LL_INFOS() << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; + LL_INFOS() << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; - LL_INFOS() << "OpenAL version: " - << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; - LL_INFOS() << "OpenAL vendor: " - << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; - LL_INFOS() << "OpenAL renderer: " - << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; + LL_INFOS() << "OpenAL version: " + << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; + LL_INFOS() << "OpenAL vendor: " + << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; + LL_INFOS() << "OpenAL renderer: " + << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; - ALint major = alutGetMajorVersion (); - ALint minor = alutGetMinorVersion (); - LL_INFOS() << "ALUT version: " << major << "." << minor << LL_ENDL; + ALint major = alutGetMajorVersion (); + ALint minor = alutGetMinorVersion (); + LL_INFOS() << "ALUT version: " << major << "." << minor << LL_ENDL; - ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); + ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); - alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); - LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL; + alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor); + LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL; - LL_INFOS() << "ALC default device: " - << ll_safe_string(alcGetString(device, - ALC_DEFAULT_DEVICE_SPECIFIER)) - << LL_ENDL; + LL_INFOS() << "ALC default device: " + << ll_safe_string(alcGetString(device, + ALC_DEFAULT_DEVICE_SPECIFIER)) + << LL_ENDL; - return true; + return true; } // virtual std::string LLAudioEngine_OpenAL::getDriverName(bool verbose) { - ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); - std::ostringstream version; - - version << - "OpenAL"; - - if (verbose) - { - version << - ", version " << - ll_safe_string(alGetString(AL_VERSION)) << - " / " << - ll_safe_string(alGetString(AL_VENDOR)) << - " / " << - ll_safe_string(alGetString(AL_RENDERER)); - - if (device) - version << - ": " << - ll_safe_string(alcGetString(device, - ALC_DEFAULT_DEVICE_SPECIFIER)); - } - - return version.str(); + ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); + std::ostringstream version; + + version << + "OpenAL"; + + if (verbose) + { + version << + ", version " << + ll_safe_string(alGetString(AL_VERSION)) << + " / " << + ll_safe_string(alGetString(AL_VENDOR)) << + " / " << + ll_safe_string(alGetString(AL_RENDERER)); + + if (device) + version << + ": " << + ll_safe_string(alcGetString(device, + ALC_DEFAULT_DEVICE_SPECIFIER)); + } + + return version.str(); } // virtual void LLAudioEngine_OpenAL::allocateListener() { - mListenerp = (LLListener *) new LLListener_OpenAL(); - if(!mListenerp) - { - LL_WARNS() << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; - } + mListenerp = (LLListener *) new LLListener_OpenAL(); + if(!mListenerp) + { + LL_WARNS() << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; + } } // virtual void LLAudioEngine_OpenAL::shutdown() { - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + // If a subsequent error occurs while there is still an error recorded + // internally, the second error will simply be ignored. + // Clear previous error to make sure we will captuare a valid failure reason + ALenum error = alutGetError(); + if (error != ALUT_ERROR_NO_ERROR) + { + LL_WARNS() << "Uncleared error state prior to shutdown: " + << alutGetErrorString(error) << LL_ENDL; + } - LL_INFOS() << "About to alutExit()" << LL_ENDL; - if(!alutExit()) - { - LL_WARNS() << "Nuts." << LL_ENDL; - LL_WARNS() << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; - } + LL_INFOS() << "About to alutExit()" << LL_ENDL; + if(!alutExit()) + { + LL_WARNS() << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; + } - LL_INFOS() << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; + LL_INFOS() << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; - delete mListenerp; - mListenerp = NULL; + delete mListenerp; + mListenerp = NULL; } LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer() { - return new LLAudioBufferOpenAL(); + return new LLAudioBufferOpenAL(); } LLAudioChannel *LLAudioEngine_OpenAL::createChannel() { - return new LLAudioChannelOpenAL(); + return new LLAudioChannelOpenAL(); } void LLAudioEngine_OpenAL::setInternalGain(F32 gain) { - //LL_INFOS() << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; - alListenerf(AL_GAIN, gain); + //LL_INFOS() << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; + alListenerf(AL_GAIN, gain); } LLAudioChannelOpenAL::LLAudioChannelOpenAL() - : - mALSource(AL_NONE), - mLastSamplePos(0) + : + mALSource(AL_NONE), + mLastSamplePos(0) { - alGenSources(1, &mALSource); + alGenSources(1, &mALSource); } LLAudioChannelOpenAL::~LLAudioChannelOpenAL() { - cleanup(); - alDeleteSources(1, &mALSource); + cleanup(); + alDeleteSources(1, &mALSource); } void LLAudioChannelOpenAL::cleanup() { - alSourceStop(mALSource); - mCurrentBufferp = NULL; + alSourceStop(mALSource); + alSourcei(mALSource, AL_BUFFER, AL_NONE); + + mCurrentBufferp = NULL; } void LLAudioChannelOpenAL::play() { - if (mALSource == AL_NONE) - { - LL_WARNS() << "Playing without a mALSource, aborting" << LL_ENDL; - return; - } - - if(!isPlaying()) - { - alSourcePlay(mALSource); - getSource()->setPlayedOnce(true); - } + if (mALSource == AL_NONE) + { + LL_WARNS() << "Playing without a mALSource, aborting" << LL_ENDL; + return; + } + + if(!isPlaying()) + { + alSourcePlay(mALSource); + getSource()->setPlayedOnce(true); + } } void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) { - if (channelp) - { - LLAudioChannelOpenAL *masterchannelp = - (LLAudioChannelOpenAL*)channelp; - if (mALSource != AL_NONE && - masterchannelp->mALSource != AL_NONE) - { - // we have channels allocated to master and slave - ALfloat master_offset; - alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, - &master_offset); - - LL_INFOS() << "Syncing with master at " << master_offset - << "sec" << LL_ENDL; - // *TODO: detect when this fails, maybe use AL_SAMPLE_ - alSourcef(mALSource, AL_SEC_OFFSET, master_offset); - } - } - play(); + if (channelp) + { + LLAudioChannelOpenAL *masterchannelp = + (LLAudioChannelOpenAL*)channelp; + if (mALSource != AL_NONE && + masterchannelp->mALSource != AL_NONE) + { + // we have channels allocated to master and slave + ALfloat master_offset; + alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, + &master_offset); + + LL_INFOS() << "Syncing with master at " << master_offset + << "sec" << LL_ENDL; + // *TODO: detect when this fails, maybe use AL_SAMPLE_ + alSourcef(mALSource, AL_SEC_OFFSET, master_offset); + } + } + play(); } bool LLAudioChannelOpenAL::isPlaying() { - if (mALSource != AL_NONE) - { - ALint state; - alGetSourcei(mALSource, AL_SOURCE_STATE, &state); - if(state == AL_PLAYING) - { - return true; - } - } - - return false; + if (mALSource != AL_NONE) + { + ALint state; + alGetSourcei(mALSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING) + { + return true; + } + } + + return false; } bool LLAudioChannelOpenAL::updateBuffer() @@ -246,306 +257,306 @@ bool LLAudioChannelOpenAL::updateBuffer() return false; } - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the source for a different buffer. - LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); - ALuint buffer = bufferp->getBuffer(); - alSourcei(mALSource, AL_BUFFER, buffer); - mLastSamplePos = 0; - } - - if (mCurrentSourcep) - { - alSourcef(mALSource, AL_GAIN, - mCurrentSourcep->getGain() * getSecondaryGain()); - alSourcei(mALSource, AL_LOOPING, - mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); - alSourcef(mALSource, AL_ROLLOFF_FACTOR, - gAudiop->mListenerp->getRolloffFactor()); - } - - return true; + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the source for a different buffer. + LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); + ALuint buffer = bufferp->getBuffer(); + alSourcei(mALSource, AL_BUFFER, buffer); + mLastSamplePos = 0; + } + + if (mCurrentSourcep) + { + alSourcef(mALSource, AL_GAIN, + mCurrentSourcep->getGain() * getSecondaryGain()); + alSourcei(mALSource, AL_LOOPING, + mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); + alSourcef(mALSource, AL_ROLLOFF_FACTOR, + gAudiop->mListenerp->getRolloffFactor()); + } + + return true; } void LLAudioChannelOpenAL::updateLoop() { - if (mALSource == AL_NONE) - { - 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. - // - ALint cur_pos; - alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); - if (cur_pos < mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; + if (mALSource == AL_NONE) + { + 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. + // + ALint cur_pos; + alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); + if (cur_pos < mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; } void LLAudioChannelOpenAL::update3DPosition() { - if(!mCurrentSourcep) - { - return; - } - if (mCurrentSourcep->isForcedPriority()) - { - alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); - alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); - } else { - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - alSourcefv(mALSource, AL_POSITION, float_pos.mV); - alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); - alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); - } - - alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); + if(!mCurrentSourcep) + { + return; + } + if (mCurrentSourcep->isForcedPriority()) + { + alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); + alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); + } else { + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + alSourcefv(mALSource, AL_POSITION, float_pos.mV); + alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); + alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + + alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); } LLAudioBufferOpenAL::LLAudioBufferOpenAL() { - mALBuffer = AL_NONE; + mALBuffer = AL_NONE; } LLAudioBufferOpenAL::~LLAudioBufferOpenAL() { - cleanup(); + cleanup(); } void LLAudioBufferOpenAL::cleanup() { - if(mALBuffer != AL_NONE) - { - alDeleteBuffers(1, &mALBuffer); - mALBuffer = AL_NONE; - } + if(mALBuffer != AL_NONE) + { + alDeleteBuffers(1, &mALBuffer); + mALBuffer = AL_NONE; + } } bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) { - cleanup(); - mALBuffer = alutCreateBufferFromFile(filename.c_str()); - if(mALBuffer == AL_NONE) - { - ALenum error = alutGetError(); - if (gDirUtilp->fileExists(filename)) - { - LL_WARNS() << - "LLAudioBufferOpenAL::loadWAV() Error loading " - << filename - << " " << alutGetErrorString(error) << LL_ENDL; - } - else - { - // It's common for the file to not actually exist. - LL_DEBUGS() << - "LLAudioBufferOpenAL::loadWAV() Error loading " - << filename - << " " << alutGetErrorString(error) << LL_ENDL; - } - return false; - } - - return true; + cleanup(); + mALBuffer = alutCreateBufferFromFile(filename.c_str()); + if(mALBuffer == AL_NONE) + { + ALenum error = alutGetError(); + if (gDirUtilp->fileExists(filename)) + { + LL_WARNS() << + "LLAudioBufferOpenAL::loadWAV() Error loading " + << filename + << " " << alutGetErrorString(error) << LL_ENDL; + } + else + { + // It's common for the file to not actually exist. + LL_DEBUGS() << + "LLAudioBufferOpenAL::loadWAV() Error loading " + << filename + << " " << alutGetErrorString(error) << LL_ENDL; + } + return false; + } + + return true; } U32 LLAudioBufferOpenAL::getLength() { - if(mALBuffer == AL_NONE) - { - return 0; - } - ALint length; - alGetBufferi(mALBuffer, AL_SIZE, &length); - return length / 2; // convert size in bytes to size in (16-bit) samples + if(mALBuffer == AL_NONE) + { + return 0; + } + ALint length; + alGetBufferi(mALBuffer, AL_SIZE, &length); + return length / 2; // convert size in bytes to size in (16-bit) samples } // ------------ bool LLAudioEngine_OpenAL::initWind() { - ALenum error; - LL_INFOS() << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; + ALenum error; + LL_INFOS() << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; + + mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; - mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; + alGetError(); /* clear error */ - alGetError(); /* clear error */ - - alGenSources(1,&mWindSource); - - if((error=alGetError()) != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL; - } + alGenSources(1,&mWindSource); + + if((error=alGetError()) != AL_NO_ERROR) + { + LL_WARNS() << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL; + } - mWindGen = new LLWindGen<WIND_SAMPLE_T>; + mWindGen = new LLWindGen<WIND_SAMPLE_T>; - mWindBufFreq = mWindGen->getInputSamplingRate(); - mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); - mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); + mWindBufFreq = mWindGen->getInputSamplingRate(); + mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); + mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); - mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; + mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; - if(mWindBuf==NULL) - { - LL_ERRS() << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL; - return false; - } + if(mWindBuf==NULL) + { + LL_ERRS() << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL; + return false; + } - LL_INFOS() << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL; + LL_INFOS() << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL; - return true; + return true; } void LLAudioEngine_OpenAL::cleanupWind() { - LL_INFOS() << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL; - - if (mWindSource != AL_NONE) - { - // detach and delete all outstanding buffers on the wind source - alSourceStop(mWindSource); - ALint processed; - alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); - while (processed--) - { - ALuint buffer = AL_NONE; - alSourceUnqueueBuffers(mWindSource, 1, &buffer); - alDeleteBuffers(1, &buffer); - } - - // delete the wind source itself - alDeleteSources(1, &mWindSource); - - mWindSource = AL_NONE; - } - - delete[] mWindBuf; - mWindBuf = NULL; - - delete mWindGen; - mWindGen = NULL; + LL_INFOS() << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL; + + if (mWindSource != AL_NONE) + { + // detach and delete all outstanding buffers on the wind source + alSourceStop(mWindSource); + ALint processed; + alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); + while (processed--) + { + ALuint buffer = AL_NONE; + alSourceUnqueueBuffers(mWindSource, 1, &buffer); + alDeleteBuffers(1, &buffer); + } + + // delete the wind source itself + alDeleteSources(1, &mWindSource); + + mWindSource = AL_NONE; + } + + delete[] mWindBuf; + mWindBuf = NULL; + + delete mWindGen; + mWindGen = NULL; } void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) { - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - ALenum error; - - if (!mEnableWind) - return; - - if(!mWindBuf) - 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]); - - 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); - - alSourcei(mWindSource, AL_LOOPING, AL_FALSE); - alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); - alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); - alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); - } - - // ok lets make a wind buffer now - - ALint processed, queued, unprocessed; - alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); - alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); - unprocessed = queued - processed; - - // ensure that there are always at least 3x as many filled buffers - // queued as we managed to empty since last time. - mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); - mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); - - //LL_INFOS() << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; - - while(processed--) // unqueue old buffers - { - ALuint buffer; - ALenum error; - alGetError(); /* clear error */ - alSourceUnqueueBuffers(mWindSource, 1, &buffer); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; - } - else - { - alDeleteBuffers(1, &buffer); - } - } - - unprocessed += mNumEmptyWindALBuffers; - while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers - { - ALuint buffer; - alGetError(); /* clear error */ - alGenBuffers(1,&buffer); - if((error=alGetError()) != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << LL_ENDL; - break; - } - - alBufferData(buffer, - AL_FORMAT_STEREO16, - mWindGen->windGenerate(mWindBuf, - mWindBufSamples), - mWindBufBytes, - mWindBufFreq); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; - } - - alSourceQueueBuffers(mWindSource, 1, &buffer); - error = alGetError(); - if(error != AL_NO_ERROR) - { - LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; - } - - --mNumEmptyWindALBuffers; - } - - ALint playing; - alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); - if(playing != AL_PLAYING) - { - alSourcePlay(mWindSource); - - LL_DEBUGS() << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; - } + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + ALenum error; + + if (!mEnableWind) + return; + + if(!mWindBuf) + 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]); + + 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); + + alSourcei(mWindSource, AL_LOOPING, AL_FALSE); + alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); + alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); + alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); + } + + // ok lets make a wind buffer now + + ALint processed, queued, unprocessed; + alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); + unprocessed = queued - processed; + + // ensure that there are always at least 3x as many filled buffers + // queued as we managed to empty since last time. + mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); + mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); + + //LL_INFOS() << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; + + while(processed--) // unqueue old buffers + { + ALuint buffer; + ALenum error; + alGetError(); /* clear error */ + alSourceUnqueueBuffers(mWindSource, 1, &buffer); + error = alGetError(); + if(error != AL_NO_ERROR) + { + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; + } + else + { + alDeleteBuffers(1, &buffer); + } + } + + unprocessed += mNumEmptyWindALBuffers; + while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers + { + ALuint buffer; + alGetError(); /* clear error */ + alGenBuffers(1,&buffer); + if((error=alGetError()) != AL_NO_ERROR) + { + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << LL_ENDL; + break; + } + + alBufferData(buffer, + AL_FORMAT_STEREO_FLOAT32, + mWindGen->windGenerate(mWindBuf, + mWindBufSamples), + mWindBufBytes, + mWindBufFreq); + error = alGetError(); + if(error != AL_NO_ERROR) + { + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; + } + + alSourceQueueBuffers(mWindSource, 1, &buffer); + error = alGetError(); + if(error != AL_NO_ERROR) + { + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; + } + + --mNumEmptyWindALBuffers; + } + + ALint playing; + alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); + if(playing != AL_PLAYING) + { + alSourcePlay(mWindSource); + + LL_DEBUGS() << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; + } } diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index 562c96c794..574bec416d 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -7,21 +7,21 @@ * $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$ */ @@ -36,73 +36,73 @@ class LLAudioEngine_OpenAL : public LLAudioEngine { - public: - LLAudioEngine_OpenAL(); - virtual ~LLAudioEngine_OpenAL(); + public: + LLAudioEngine_OpenAL(); + virtual ~LLAudioEngine_OpenAL(); virtual bool init(void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const { return nullptr; } - virtual void allocateListener(); + virtual void allocateListener(); - virtual void shutdown(); + virtual void shutdown(); - void setInternalGain(F32 gain); + void setInternalGain(F32 gain); - LLAudioBuffer* createBuffer(); - LLAudioChannel* createChannel(); + LLAudioBuffer* createBuffer(); + LLAudioChannel* createChannel(); - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); - /*virtual*/ void updateWind(LLVector3 direction, F32 camera_altitude); + /*virtual*/ bool initWind(); + /*virtual*/ void cleanupWind(); + /*virtual*/ void updateWind(LLVector3 direction, F32 camera_altitude); - private: - typedef S16 WIND_SAMPLE_T; - LLWindGen<WIND_SAMPLE_T> *mWindGen; - S16 *mWindBuf; - U32 mWindBufFreq; - U32 mWindBufSamples; - U32 mWindBufBytes; - ALuint mWindSource; + private: + typedef F32 WIND_SAMPLE_T; + LLWindGen<WIND_SAMPLE_T> *mWindGen; + F32 *mWindBuf; + U32 mWindBufFreq; + U32 mWindBufSamples; + U32 mWindBufBytes; + ALuint mWindSource; int mNumEmptyWindALBuffers; - static const int MAX_NUM_WIND_BUFFERS = 80; - static const float WIND_BUFFER_SIZE_SEC; // 1/20th sec + static const int MAX_NUM_WIND_BUFFERS = 80; + static const float WIND_BUFFER_SIZE_SEC; // 1/20th sec }; class LLAudioChannelOpenAL : public LLAudioChannel { - public: - LLAudioChannelOpenAL(); - virtual ~LLAudioChannelOpenAL(); - protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); - - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); - - ALuint mALSource; - ALint mLastSamplePos; + public: + LLAudioChannelOpenAL(); + virtual ~LLAudioChannelOpenAL(); + protected: + /*virtual*/ void play(); + /*virtual*/ void playSynced(LLAudioChannel *channelp); + /*virtual*/ void cleanup(); + /*virtual*/ bool isPlaying(); + + /*virtual*/ bool updateBuffer(); + /*virtual*/ void update3DPosition(); + /*virtual*/ void updateLoop(); + + ALuint mALSource; + ALint mLastSamplePos; }; class LLAudioBufferOpenAL : public LLAudioBuffer{ - public: - LLAudioBufferOpenAL(); - virtual ~LLAudioBufferOpenAL(); + public: + LLAudioBufferOpenAL(); + virtual ~LLAudioBufferOpenAL(); - bool loadWAV(const std::string& filename); - U32 getLength(); + bool loadWAV(const std::string& filename); + U32 getLength(); - friend class LLAudioChannelOpenAL; - protected: - void cleanup(); - ALuint getBuffer() {return mALBuffer;} + friend class LLAudioChannelOpenAL; + protected: + void cleanup(); + ALuint getBuffer() {return mALBuffer;} - ALuint mALBuffer; + ALuint mALBuffer; }; #endif diff --git a/indra/llaudio/lllistener.cpp b/indra/llaudio/lllistener.cpp index df2366c8c2..663121d6bc 100644 --- a/indra/llaudio/lllistener.cpp +++ b/indra/llaudio/lllistener.cpp @@ -1,25 +1,25 @@ -/** +/** * @file listener.cpp * @brief Implementation of LISTENER class abstracting the audio support * * $LicenseInfo:firstyear=2000&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$ */ @@ -36,7 +36,7 @@ //----------------------------------------------------------------------- LLListener::LLListener() { - init(); + init(); } //----------------------------------------------------------------------- @@ -47,64 +47,64 @@ LLListener::~LLListener() //----------------------------------------------------------------------- void LLListener::init(void) { - mPosition.zeroVec(); - mListenAt.setVec(DEFAULT_AT); - mListenUp.setVec(DEFAULT_UP); - mVelocity.zeroVec(); + mPosition.zeroVec(); + mListenAt.setVec(DEFAULT_AT); + mListenUp.setVec(DEFAULT_UP); + mVelocity.zeroVec(); } //----------------------------------------------------------------------- void LLListener::translate(LLVector3 offset) { - mPosition += offset; + mPosition += offset; } //----------------------------------------------------------------------- void LLListener::setPosition(LLVector3 pos) { - mPosition = pos; + mPosition = pos; } //----------------------------------------------------------------------- LLVector3 LLListener::getPosition(void) { - return(mPosition); + return(mPosition); } //----------------------------------------------------------------------- LLVector3 LLListener::getAt(void) { - return(mListenAt); + return(mListenAt); } //----------------------------------------------------------------------- LLVector3 LLListener::getUp(void) { - return(mListenUp); + return(mListenUp); } //----------------------------------------------------------------------- void LLListener::setVelocity(LLVector3 vel) { - mVelocity = vel; + mVelocity = vel; } //----------------------------------------------------------------------- void LLListener::orient(LLVector3 up, LLVector3 at) { - mListenUp = up; - mListenAt = at; + mListenUp = up; + mListenAt = at; } //----------------------------------------------------------------------- void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) { - mPosition = pos; - mVelocity = vel; + mPosition = pos; + mVelocity = vel; - setPosition(pos); - setVelocity(vel); - orient(up,at); + setPosition(pos); + setVelocity(vel); + orient(up,at); } //----------------------------------------------------------------------- @@ -115,7 +115,7 @@ void LLListener::setDopplerFactor(F32 factor) //----------------------------------------------------------------------- F32 LLListener::getDopplerFactor() { - return (1.f); + return (1.f); } //----------------------------------------------------------------------- @@ -126,7 +126,7 @@ void LLListener::setRolloffFactor(F32 factor) //----------------------------------------------------------------------- F32 LLListener::getRolloffFactor() { - return (1.f); + return (1.f); } //----------------------------------------------------------------------- diff --git a/indra/llaudio/lllistener.h b/indra/llaudio/lllistener.h index 41836bf039..b1142cffb2 100644 --- a/indra/llaudio/lllistener.h +++ b/indra/llaudio/lllistener.h @@ -1,25 +1,25 @@ -/** +/** * @file listener.h * @brief Description of LISTENER base class abstracting the audio support. * * $LicenseInfo:firstyear=2000&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$ */ @@ -29,43 +29,43 @@ #include "v3math.h" -class LLListener +class LLListener { private: protected: - LLVector3 mPosition; - LLVector3 mVelocity; - LLVector3 mListenAt; - LLVector3 mListenUp; + LLVector3 mPosition; + LLVector3 mVelocity; + LLVector3 mListenAt; + LLVector3 mListenUp; public: private: protected: - public: - LLListener(); - virtual ~LLListener(); - virtual void init(); + public: + LLListener(); + virtual ~LLListener(); + virtual void init(); - virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); + virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void translate(LLVector3 offset); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void translate(LLVector3 offset); - virtual void setDopplerFactor(F32 factor); - virtual void setRolloffFactor(F32 factor); + virtual void setDopplerFactor(F32 factor); + virtual void setRolloffFactor(F32 factor); - virtual LLVector3 getPosition(); - virtual LLVector3 getAt(); - virtual LLVector3 getUp(); + virtual LLVector3 getPosition(); + virtual LLVector3 getAt(); + virtual LLVector3 getUp(); - virtual F32 getDopplerFactor(); - virtual F32 getRolloffFactor(); + virtual F32 getDopplerFactor(); + virtual F32 getRolloffFactor(); - virtual void commitDeferredChanges(); + virtual void commitDeferredChanges(); }; #endif diff --git a/indra/llaudio/lllistener_ds3d.h b/indra/llaudio/lllistener_ds3d.h index 9150ccd5b9..22cd158507 100644 --- a/indra/llaudio/lllistener_ds3d.h +++ b/indra/llaudio/lllistener_ds3d.h @@ -1,4 +1,4 @@ -/** +/** * @file listener_ds3d.h * @brief Description of LISTENER class abstracting the audio support * as a DirectSound 3D implementation (windows only) @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2000&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$ */ @@ -38,29 +38,29 @@ class LLListener_DS3D : public LLListener { private: protected: - IDirectSound3DListener8 *m3DListener; + IDirectSound3DListener8 *m3DListener; public: private: protected: - public: - LLListener_DS3D(); - virtual ~LLListener_DS3D(); - virtual void init(); + public: + LLListener_DS3D(); + virtual ~LLListener_DS3D(); + virtual void init(); - virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); + virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); - virtual void commitDeferredChanges(); + virtual void commitDeferredChanges(); }; #endif diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp deleted file mode 100644 index abd5e345b5..0000000000 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @file listener_fmodstudio.cpp - * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llaudioengine.h" -#include "lllistener_fmodstudio.h" -#include "fmodstudio/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); - - // at = -at; by default Fmod studio is 'left-handed' but we are providing - // flag FMOD_INIT_3D_RIGHTHANDED so no correction are needed - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::commitDeferredChanges() -{ - if (!mSystem) - { - return; - } - - mSystem->update(); -} - - -void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) -{ - //An internal FMOD optimization skips 3D updates if there have not been changes to the 3D sound environment. - // (this was true for FMODex, looks to be still true for FMOD STUDIO, but needs a recheck) - //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. - //In short: Changing the position ticks a dirtyflag inside fmod, which makes it not skip 3D processing next update call. - if (mRolloffFactor != factor) - { - LLVector3 pos = mPosition - LLVector3(0.f, 0.f, .1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODSTUDIO::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODSTUDIO::getDopplerFactor() -{ - return mDopplerFactor; -} diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h deleted file mode 100644 index 6ad85d9700..0000000000 --- a/indra/llaudio/lllistener_fmodstudio.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file listener_fmodstudio.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_FMODSTUDIO_H -#define LL_LISTENER_FMODSTUDIO_H - -#include "lllistener.h" - -//Stubs -namespace FMOD -{ - class System; -} - -//Interfaces -class LLListener_FMODSTUDIO : public LLListener -{ -public: - LLListener_FMODSTUDIO(FMOD::System *system); - virtual ~LLListener_FMODSTUDIO(); - virtual void init(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); -protected: - FMOD::System *mSystem; - F32 mDopplerFactor; - F32 mRolloffFactor; -}; - -#endif - - diff --git a/indra/llaudio/lllistener_openal.cpp b/indra/llaudio/lllistener_openal.cpp index 9dd4c86854..2934dc1889 100644 --- a/indra/llaudio/lllistener_openal.cpp +++ b/indra/llaudio/lllistener_openal.cpp @@ -6,21 +6,21 @@ * $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$ */ @@ -32,7 +32,7 @@ LLListener_OpenAL::LLListener_OpenAL() { - init(); + init(); } LLListener_OpenAL::~LLListener_OpenAL() @@ -41,70 +41,70 @@ LLListener_OpenAL::~LLListener_OpenAL() void LLListener_OpenAL::translate(LLVector3 offset) { - //LL_INFOS() << "LLListener_OpenAL::translate() : " << offset << LL_ENDL; - LLListener::translate(offset); + //LL_INFOS() << "LLListener_OpenAL::translate() : " << offset << LL_ENDL; + LLListener::translate(offset); } void LLListener_OpenAL::setPosition(LLVector3 pos) { - //LL_INFOS() << "LLListener_OpenAL::setPosition() : " << pos << LL_ENDL; - LLListener::setPosition(pos); + //LL_INFOS() << "LLListener_OpenAL::setPosition() : " << pos << LL_ENDL; + LLListener::setPosition(pos); } void LLListener_OpenAL::setVelocity(LLVector3 vel) { - LLListener::setVelocity(vel); + LLListener::setVelocity(vel); } void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at) { - //LL_INFOS() << "LLListener_OpenAL::orient() up: " << up << " at: " << at << LL_ENDL; - LLListener::orient(up, at); + //LL_INFOS() << "LLListener_OpenAL::orient() up: " << up << " at: " << at << LL_ENDL; + LLListener::orient(up, at); } void LLListener_OpenAL::commitDeferredChanges() { - ALfloat orientation[6]; - orientation[0] = mListenAt.mV[0]; - orientation[1] = mListenAt.mV[1]; - orientation[2] = mListenAt.mV[2]; - orientation[3] = mListenUp.mV[0]; - orientation[4] = mListenUp.mV[1]; - orientation[5] = mListenUp.mV[2]; - - ALfloat velocity[3]; - velocity[0] = mVelocity.mV[0]; - velocity[1] = mVelocity.mV[1]; - velocity[2] = mVelocity.mV[2]; - - alListenerfv(AL_ORIENTATION, orientation); - alListenerfv(AL_POSITION, mPosition.mV); - alListenerfv(AL_VELOCITY, velocity); + ALfloat orientation[6]; + orientation[0] = mListenAt.mV[0]; + orientation[1] = mListenAt.mV[1]; + orientation[2] = mListenAt.mV[2]; + orientation[3] = mListenUp.mV[0]; + orientation[4] = mListenUp.mV[1]; + orientation[5] = mListenUp.mV[2]; + + ALfloat velocity[3]; + velocity[0] = mVelocity.mV[0]; + velocity[1] = mVelocity.mV[1]; + velocity[2] = mVelocity.mV[2]; + + alListenerfv(AL_ORIENTATION, orientation); + alListenerfv(AL_POSITION, mPosition.mV); + alListenerfv(AL_VELOCITY, velocity); } void LLListener_OpenAL::setDopplerFactor(F32 factor) { - //LL_INFOS() << "LLListener_OpenAL::setDopplerFactor() : " << factor << LL_ENDL; - alDopplerFactor(factor); + //LL_INFOS() << "LLListener_OpenAL::setDopplerFactor() : " << factor << LL_ENDL; + alDopplerFactor(factor); } F32 LLListener_OpenAL::getDopplerFactor() { - ALfloat factor; - factor = alGetFloat(AL_DOPPLER_FACTOR); - //LL_INFOS() << "LLListener_OpenAL::getDopplerFactor() : " << factor << LL_ENDL; - return factor; + ALfloat factor; + factor = alGetFloat(AL_DOPPLER_FACTOR); + //LL_INFOS() << "LLListener_OpenAL::getDopplerFactor() : " << factor << LL_ENDL; + return factor; } void LLListener_OpenAL::setRolloffFactor(F32 factor) { - mRolloffFactor = factor; + mRolloffFactor = factor; } F32 LLListener_OpenAL::getRolloffFactor() { - return mRolloffFactor; + return mRolloffFactor; } diff --git a/indra/llaudio/lllistener_openal.h b/indra/llaudio/lllistener_openal.h index cb163b11a5..f1b69ddcef 100644 --- a/indra/llaudio/lllistener_openal.h +++ b/indra/llaudio/lllistener_openal.h @@ -1,4 +1,4 @@ -/** +/** * @file listener_openal.h * @brief Description of LISTENER class abstracting the audio support * as an OpenAL implementation @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2000&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$ */ @@ -32,26 +32,27 @@ #include "AL/al.h" #include "AL/alut.h" +#include "AL/alext.h" class LLListener_OpenAL : public LLListener { - public: - LLListener_OpenAL(); - virtual ~LLListener_OpenAL(); + public: + LLListener_OpenAL(); + virtual ~LLListener_OpenAL(); - 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 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(); + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); protected: - F32 mRolloffFactor; + F32 mRolloffFactor; }; #endif diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h index 93479f9d59..3a024d8db8 100644 --- a/indra/llaudio/llstreamingaudio.h +++ b/indra/llaudio/llstreamingaudio.h @@ -1,4 +1,4 @@ -/** +/** * @file streamingaudio.h * @author Tofu Linden * @brief Definition of LLStreamingAudioInterface base class abstracting the streaming audio interface @@ -6,21 +6,21 @@ * $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$ */ @@ -34,19 +34,19 @@ class LLStreamingAudioInterface { public: - virtual ~LLStreamingAudioInterface() {} + virtual ~LLStreamingAudioInterface() {} - virtual void start(const std::string& url) = 0; - virtual void stop() = 0; - virtual void pause(int pause) = 0; - virtual void update() = 0; - virtual int isPlaying() = 0; - // use a value from 0.0 to 1.0, inclusive - virtual void setGain(F32 vol) = 0; - virtual F32 getGain() = 0; - virtual std::string getURL() = 0; - virtual bool supportsAdjustableBufferSizes(){return false;} - virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){}; + virtual void start(const std::string& url) = 0; + virtual void stop() = 0; + virtual void pause(int pause) = 0; + virtual void update() = 0; + virtual int isPlaying() = 0; + // use a value from 0.0 to 1.0, inclusive + virtual void setGain(F32 vol) = 0; + virtual F32 getGain() = 0; + virtual std::string getURL() = 0; + virtual bool supportsAdjustableBufferSizes(){return false;} + virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){}; }; #endif // LL_STREAMINGAUDIO_H diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp deleted file mode 100644 index 85577992a6..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/** - * @file streamingaudio_fmodstudio.cpp - * @brief LLStreamingAudio_FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, 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 "fmodstudio/fmod.hpp" -#include "fmodstudio/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), -mRetryCount(0) -{ - // 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 - FMOD_RESULT result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL; - } - - // 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() -{ - if (mCurrentInternetStreamp) - { - // Isn't supposed to hapen, stream should be clear by now, - // and if it does, we are likely going to crash. - LL_WARNS("FMOD") << "mCurrentInternetStreamp not null on shutdown!" << LL_ENDL; - stop(); - } - - // Kill dead internet streams, if possible - killDeadStreams(); - - if (!mDeadStreams.empty()) - { - // LLStreamingAudio_FMODSTUDIO was inited on startup - // and should be destroyed on shutdown, it should - // wait for streams to die to not cause crashes or - // leaks. - // Ideally we need to wait on some kind of callback - // to release() streams correctly, but 200 ms should - // be enough and we can't wait forever. - LL_INFOS("FMOD") << "Waiting for " << (S32)mDeadStreams.size() << " streams to stop" << LL_ENDL; - for (S32 i = 0; i < 20; i++) - { - const U32 ms_delay = 10; - ms_sleep(ms_delay); // rude, but not many options here - killDeadStreams(); - if (mDeadStreams.empty()) - { - LL_INFOS("FMOD") << "All streams stopped after " << (S32)((i + 1) * ms_delay) << "ms" << LL_ENDL; - break; - } - } - } - - if (!mDeadStreams.empty()) - { - LL_WARNS("FMOD") << "Failed to kill some audio streams" << LL_ENDL; - } -} - -void LLStreamingAudio_FMODSTUDIO::killDeadStreams() -{ - std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODSTUDIO *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS("FMOD") << "Closed dead stream" << LL_ENDL; - delete streamp; - iter = mDeadStreams.erase(iter); - } - else - { - iter++; - } - } -} - -void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) -{ - //if (!mInited) - //{ - // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; - // return; - //} - - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); - - if (!url.empty()) - { - LL_INFOS("FMOD") << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); - mURL = url; - } - else - { - LL_INFOS("FMOD") << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } - - mRetryCount = 0; -} - - -void LLStreamingAudio_FMODSTUDIO::update() -{ - // Kill dead internet streams, if possible - killDeadStreams(); - - // 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); - } - mRetryCount = 0; - } - else if (open_state == FMOD_OPENSTATE_ERROR) - { - LL_INFOS("FMOD") << "State: FMOD_OPENSTATE_ERROR" - << " Progress: " << U32(progress) - << " Starving: " << S32(starving) - << " Diskbusy: " << S32(diskbusy) << LL_ENDL; - if (mRetryCount < 2) - { - // Retry - std::string url = mURL; - stop(); // might drop mURL, drops mCurrentInternetStreamp - - mRetryCount++; - - if (!url.empty()) - { - LL_INFOS("FMOD") << "Restarting internet stream: " << url << ", attempt " << (mRetryCount + 1) << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); - mURL = url; - } - } - else - { - stop(); - } - return; - } - - if (mFMODInternetStreamChannelp) - { - 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) - { - for (S32 i = 0; i < tagcount; ++i) - { - if (sound->getTag(NULL, i, &tag) != FMOD_OK) - continue; - - if (tag.type == FMOD_TAGTYPE_FMOD) - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS("FMOD") << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - } - } - - if (starving) - { - bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if (!paused) - { - LL_INFOS("FMOD") << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS("FMOD") << " (diskbusy=" << diskbusy << ")" << LL_ENDL; - LL_INFOS("FMOD") << " (progress=" << progress << ")" << LL_ENDL; - mFMODInternetStreamChannelp->setPaused(true); - } - } - else if (progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODSTUDIO::stop() -{ - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - mFMODInternetStreamChannelp = NULL; - } - - if (mCurrentInternetStreamp) - { - LL_INFOS("FMOD") << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS("FMOD") << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - 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) - { - LL_INFOS("FMOD") << "Pausing internet stream" << LL_ENDL; - 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()) - { - 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); - } -} - -/////////////////////////////////////////////////////// -// 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) - { - LL_WARNS("FMOD") << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) - { - LL_WARNS("FMOD") << "No internet stream to start playing!" << LL_ENDL; - return NULL; - } - - if (mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - FMOD_RESULT result = mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL; - } - 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(); - 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; - FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL; - } - return state; -} - -void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) -{ - FMOD_RESULT result = mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL; - return; - } - FMOD_ADVANCEDSETTINGS settings; - memset(&settings, 0, sizeof(settings)); - settings.cbSize = sizeof(settings); - settings.defaultDecodeBufferSize = decodebuffertime;//ms - result = mSystem->setAdvancedSettings(&settings); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setAdvancedSettings error: " << FMOD_ErrorString(result) << LL_ENDL; - } -} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h deleted file mode 100644 index 35a7b1226e..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file streamingaudio_fmodstudio.h - * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H -#define LL_STREAMINGAUDIO_FMODSTUDIO_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODSTUDIO; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface -{ -public: - LLStreamingAudio_FMODSTUDIO(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); - - /*virtual*/ void start(const std::string& url); - /*virtual*/ void stop(); - /*virtual*/ void pause(S32 pause); - /*virtual*/ void update(); - /*virtual*/ S32 isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} - /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); -private: - void killDeadStreams(); - - FMOD::System *mSystem; - - LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams; - - std::string mURL; - F32 mGain; - S32 mRetryCount; -}; - - -#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index 2e1ed9b505..83e7fad92f 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -1,25 +1,25 @@ -/** +/** * @file vorbisencode.cpp * @brief Vorbis encoding routine routine for Indra. * * $LicenseInfo:firstyear=2000&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$ */ @@ -39,161 +39,161 @@ #if 0 #include "VorbisFramework.h" -#define vorbis_analysis mac_vorbis_analysis -#define vorbis_analysis_headerout mac_vorbis_analysis_headerout -#define vorbis_analysis_init mac_vorbis_analysis_init -#define vorbis_encode_ctl mac_vorbis_encode_ctl -#define vorbis_encode_setup_init mac_vorbis_encode_setup_init -#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed - -#define vorbis_info_init mac_vorbis_info_init -#define vorbis_info_clear mac_vorbis_info_clear -#define vorbis_comment_init mac_vorbis_comment_init -#define vorbis_comment_clear mac_vorbis_comment_clear -#define vorbis_block_init mac_vorbis_block_init -#define vorbis_block_clear mac_vorbis_block_clear -#define vorbis_dsp_clear mac_vorbis_dsp_clear -#define vorbis_analysis_buffer mac_vorbis_analysis_buffer -#define vorbis_analysis_wrote mac_vorbis_analysis_wrote -#define vorbis_analysis_blockout mac_vorbis_analysis_blockout - -#define ogg_stream_packetin mac_ogg_stream_packetin -#define ogg_stream_init mac_ogg_stream_init -#define ogg_stream_flush mac_ogg_stream_flush -#define ogg_stream_pageout mac_ogg_stream_pageout -#define ogg_page_eos mac_ogg_page_eos -#define ogg_stream_clear mac_ogg_stream_clear +#define vorbis_analysis mac_vorbis_analysis +#define vorbis_analysis_headerout mac_vorbis_analysis_headerout +#define vorbis_analysis_init mac_vorbis_analysis_init +#define vorbis_encode_ctl mac_vorbis_encode_ctl +#define vorbis_encode_setup_init mac_vorbis_encode_setup_init +#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed + +#define vorbis_info_init mac_vorbis_info_init +#define vorbis_info_clear mac_vorbis_info_clear +#define vorbis_comment_init mac_vorbis_comment_init +#define vorbis_comment_clear mac_vorbis_comment_clear +#define vorbis_block_init mac_vorbis_block_init +#define vorbis_block_clear mac_vorbis_block_clear +#define vorbis_dsp_clear mac_vorbis_dsp_clear +#define vorbis_analysis_buffer mac_vorbis_analysis_buffer +#define vorbis_analysis_wrote mac_vorbis_analysis_wrote +#define vorbis_analysis_blockout mac_vorbis_analysis_blockout + +#define ogg_stream_packetin mac_ogg_stream_packetin +#define ogg_stream_init mac_ogg_stream_init +#define ogg_stream_flush mac_ogg_stream_flush +#define ogg_stream_pageout mac_ogg_stream_pageout +#define ogg_page_eos mac_ogg_page_eos +#define ogg_stream_clear mac_ogg_stream_clear #endif S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& error_msg) { - U16 num_channels = 0; - U32 sample_rate = 0; - U32 bits_per_sample = 0; - U32 physical_file_size = 0; - U32 chunk_length = 0; - U32 raw_data_length = 0; - U32 bytes_per_sec = 0; - BOOL uncompressed_pcm = FALSE; + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + U32 physical_file_size = 0; + U32 chunk_length = 0; + U32 raw_data_length = 0; + U32 bytes_per_sec = 0; + bool uncompressed_pcm = false; - unsigned char wav_header[44]; /*Flawfinder: ignore*/ + unsigned char wav_header[44]; /*Flawfinder: ignore*/ - error_msg.clear(); + error_msg.clear(); - //******************************** - LLAPRFile infile ; + //******************************** + LLAPRFile infile ; infile.open(in_fname,LL_APR_RB); - //******************************** - if (!infile.getFileHandle()) - { - error_msg = "CannotUploadSoundFile"; - return(LLVORBISENC_SOURCE_OPEN_ERR); - } - - infile.read(wav_header, 44); - physical_file_size = infile.seek(APR_END,0); - - if (strncmp((char *)&(wav_header[0]),"RIFF",4)) - { - error_msg = "SoundFileNotRIFF"; - return(LLVORBISENC_WAV_FORMAT_ERR); - } - - if (strncmp((char *)&(wav_header[8]),"WAVE",4)) - { - error_msg = "SoundFileNotRIFF"; - return(LLVORBISENC_WAV_FORMAT_ERR); - } - - // parse the chunks - - U32 file_pos = 12; // start at the first chunk (usually fmt but not always) - - while ((file_pos + 8)< physical_file_size) - { - infile.seek(APR_SET,file_pos); - infile.read(wav_header, 44); - - chunk_length = ((U32) wav_header[7] << 24) - + ((U32) wav_header[6] << 16) - + ((U32) wav_header[5] << 8) - + wav_header[4]; - - if (chunk_length > physical_file_size - file_pos - 4) - { - infile.close(); - error_msg = "SoundFileInvalidChunkSize"; - return(LLVORBISENC_CHUNK_SIZE_ERR); - } - -// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; - - if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) - { - if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00)) - { - uncompressed_pcm = TRUE; - } - num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; - sample_rate = ((U32) wav_header[15] << 24) - + ((U32) wav_header[14] << 16) - + ((U32) wav_header[13] << 8) - + wav_header[12]; - bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; - bytes_per_sec = ((U32) wav_header[19] << 24) - + ((U32) wav_header[18] << 16) - + ((U32) wav_header[17] << 8) - + wav_header[16]; - } - else if (!(strncmp((char *)&(wav_header[0]),"data",4))) - { - raw_data_length = chunk_length; - } - file_pos += (chunk_length + 8); - chunk_length = 0; - } - //**************** - infile.close(); - //**************** - - if (!uncompressed_pcm) - { - error_msg = "SoundFileNotPCM"; - return(LLVORBISENC_PCM_FORMAT_ERR); - } - - if ((num_channels < 1) || (num_channels > LLVORBIS_CLIP_MAX_CHANNELS)) - { - error_msg = "SoundFileInvalidChannelCount"; - return(LLVORBISENC_MULTICHANNEL_ERR); - } - - if (sample_rate != LLVORBIS_CLIP_SAMPLE_RATE) - { - error_msg = "SoundFileInvalidSampleRate"; - return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE); - } - - if ((bits_per_sample != 16) && (bits_per_sample != 8)) - { - error_msg = "SoundFileInvalidWordSize"; - return(LLVORBISENC_UNSUPPORTED_WORD_SIZE); - } - - if (!raw_data_length) - { - error_msg = "SoundFileInvalidHeader"; - return(LLVORBISENC_CLIP_TOO_LONG); - } - - F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec; - - if (clip_length > LLVORBIS_CLIP_MAX_TIME) - { - error_msg = "SoundFileInvalidTooLong"; - return(LLVORBISENC_CLIP_TOO_LONG); - } + //******************************** + if (!infile.getFileHandle()) + { + error_msg = "CannotUploadSoundFile"; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + infile.read(wav_header, 44); + physical_file_size = infile.seek(APR_END,0); + + if (strncmp((char *)&(wav_header[0]),"RIFF",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + if (strncmp((char *)&(wav_header[8]),"WAVE",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + // parse the chunks + + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while ((file_pos + 8)< physical_file_size) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + + if (chunk_length > physical_file_size - file_pos - 4) + { + infile.close(); + error_msg = "SoundFileInvalidChunkSize"; + return(LLVORBISENC_CHUNK_SIZE_ERR); + } + +// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00)) + { + uncompressed_pcm = true; + } + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + bytes_per_sec = ((U32) wav_header[19] << 24) + + ((U32) wav_header[18] << 16) + + ((U32) wav_header[17] << 8) + + wav_header[16]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + raw_data_length = chunk_length; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + //**************** + infile.close(); + //**************** + + if (!uncompressed_pcm) + { + error_msg = "SoundFileNotPCM"; + return(LLVORBISENC_PCM_FORMAT_ERR); + } + + if ((num_channels < 1) || (num_channels > LLVORBIS_CLIP_MAX_CHANNELS)) + { + error_msg = "SoundFileInvalidChannelCount"; + return(LLVORBISENC_MULTICHANNEL_ERR); + } + + if (sample_rate != LLVORBIS_CLIP_SAMPLE_RATE) + { + error_msg = "SoundFileInvalidSampleRate"; + return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE); + } + + if ((bits_per_sample != 16) && (bits_per_sample != 8)) + { + error_msg = "SoundFileInvalidWordSize"; + return(LLVORBISENC_UNSUPPORTED_WORD_SIZE); + } + + if (!raw_data_length) + { + error_msg = "SoundFileInvalidHeader"; + return(LLVORBISENC_CLIP_TOO_LONG); + } + + F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec; + + if (clip_length > LLVORBIS_CLIP_MAX_TIME) + { + error_msg = "SoundFileInvalidTooLong"; + return(LLVORBISENC_CLIP_TOO_LONG); + } return(LLVORBISENC_NOERR); } @@ -201,306 +201,306 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname) { #define READ_BUFFER 1024 - unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/ - - ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ - ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ - ogg_packet op; /* one raw packet of data for decode */ - - vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ - vorbis_comment vc; /* struct that stores all the user comments */ - - vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ - vorbis_block vb; /* local working space for packet->PCM decode */ - - int eos=0; - int result; - - U16 num_channels = 0; - U32 sample_rate = 0; - U32 bits_per_sample = 0; - - S32 format_error = 0; - std::string error_msg; - if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) - { - LL_WARNS() << error_msg << ": " << in_fname << LL_ENDL; - return(format_error); - } + unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/ + + ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + int eos=0; + int result; + + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + + S32 format_error = 0; + std::string error_msg; + if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) + { + LL_WARNS() << error_msg << ": " << in_fname << LL_ENDL; + return(format_error); + } #if 1 - unsigned char wav_header[44]; /*Flawfinder: ignore*/ - - S32 data_left = 0; - - LLAPRFile infile ; - infile.open(in_fname,LL_APR_RB); - if (!infile.getFileHandle()) - { - LL_WARNS() << "Couldn't open temporary ogg file for writing: " << in_fname - << LL_ENDL; - return(LLVORBISENC_SOURCE_OPEN_ERR); - } - - LLAPRFile outfile ; - outfile.open(out_fname,LL_APR_WPB); - if (!outfile.getFileHandle()) - { - LL_WARNS() << "Couldn't open upload sound file for reading: " << in_fname - << LL_ENDL; - return(LLVORBISENC_DEST_OPEN_ERR); - } - - // parse the chunks - U32 chunk_length = 0; - U32 file_pos = 12; // start at the first chunk (usually fmt but not always) - - while (infile.eof() != APR_EOF) - { - infile.seek(APR_SET,file_pos); - infile.read(wav_header, 44); - - chunk_length = ((U32) wav_header[7] << 24) - + ((U32) wav_header[6] << 16) - + ((U32) wav_header[5] << 8) - + wav_header[4]; - -// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; - - if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) - { - num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; - sample_rate = ((U32) wav_header[15] << 24) - + ((U32) wav_header[14] << 16) - + ((U32) wav_header[13] << 8) - + wav_header[12]; - bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; - } - else if (!(strncmp((char *)&(wav_header[0]),"data",4))) - { - infile.seek(APR_SET,file_pos+8); - // leave the file pointer at the beginning of the data chunk data - data_left = chunk_length; - break; - } - file_pos += (chunk_length + 8); - chunk_length = 0; - } - - - /********** Encode setup ************/ - - /* choose an encoding mode */ - /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ - vorbis_info_init(&vi); - - // always encode to mono - - // SL-52913 & SL-53779 determined this quality level to be our 'good - // enough' general-purpose quality level with a nice low bitrate. - // Equivalent to oggenc -q0.5 - F32 quality = 0.05f; -// quality = (bitrate==128000 ? 0.4f : 0.1); - -// if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1)) - if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality)) -// if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) || -// vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || -// vorbis_encode_setup_init(&vi)) - { - LL_WARNS() << "unable to initialize vorbis codec at quality " << quality << LL_ENDL; - // LL_WARNS() << "unable to initialize vorbis codec at bitrate " << bitrate << LL_ENDL; - return(LLVORBISENC_DEST_OPEN_ERR); - } - - /* add a comment */ - vorbis_comment_init(&vc); -// vorbis_comment_add(&vc,"Linden"); - - /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init(&vd,&vi); - vorbis_block_init(&vd,&vb); - - /* set up our packet->stream encoder */ - /* pick a random serial number; that way we can more likely build - chained streams just by concatenation */ - ogg_stream_init(&os, ll_rand()); - - /* Vorbis streams begin with three headers; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. The - third header holds the bitstream codebook. We merely need to - make the headers, then pass them to libvorbis one at a time; - libvorbis handles the additional Ogg bitstream constraints */ - - { - ogg_packet header; - ogg_packet header_comm; - ogg_packet header_code; - - vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); - ogg_stream_packetin(&os,&header); /* automatically placed in its own - page */ - ogg_stream_packetin(&os,&header_comm); - ogg_stream_packetin(&os,&header_code); - - /* We don't have to write out here, but doing so makes streaming - * much easier, so we do, flushing ALL pages. This ensures the actual - * audio data will start on a new page - */ - while(!eos){ - int result=ogg_stream_flush(&os,&og); - if(result==0)break; - outfile.write(og.header, og.header_len); - outfile.write(og.body, og.body_len); - } - - } - - - while(!eos) - { - long bytes_per_sample = bits_per_sample/8; - - long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ - - if (bytes==0) - { - /* end of file. this can be done implicitly in the mainline, - but it's easier to see here in non-clever fashion. - Tell the library we're at end of stream so that it can handle - the last frame and mark end of stream in the output properly */ - - vorbis_analysis_wrote(&vd,0); -// eos = 1; - - } - else - { - long i; - long samples; - int temp; - - data_left -= bytes; + unsigned char wav_header[44]; /*Flawfinder: ignore*/ + + S32 data_left = 0; + + LLAPRFile infile ; + infile.open(in_fname,LL_APR_RB); + if (!infile.getFileHandle()) + { + LL_WARNS() << "Couldn't open temporary ogg file for writing: " << in_fname + << LL_ENDL; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + LLAPRFile outfile ; + outfile.open(out_fname,LL_APR_WPB); + if (!outfile.getFileHandle()) + { + LL_WARNS() << "Couldn't open upload sound file for reading: " << in_fname + << LL_ENDL; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + // parse the chunks + U32 chunk_length = 0; + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while (infile.eof() != APR_EOF) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + +// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + infile.seek(APR_SET,file_pos+8); + // leave the file pointer at the beginning of the data chunk data + data_left = chunk_length; + break; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + + + /********** Encode setup ************/ + + /* choose an encoding mode */ + /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ + vorbis_info_init(&vi); + + // always encode to mono + + // SL-52913 & SL-53779 determined this quality level to be our 'good + // enough' general-purpose quality level with a nice low bitrate. + // Equivalent to oggenc -q0.5 + F32 quality = 0.05f; +// quality = (bitrate==128000 ? 0.4f : 0.1); + +// if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1)) + if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality)) +// if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) || +// vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || +// vorbis_encode_setup_init(&vi)) + { + LL_WARNS() << "unable to initialize vorbis codec at quality " << quality << LL_ENDL; + // LL_WARNS() << "unable to initialize vorbis codec at bitrate " << bitrate << LL_ENDL; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + /* add a comment */ + vorbis_comment_init(&vc); +// vorbis_comment_add(&vc,"Linden"); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init(&vd,&vi); + vorbis_block_init(&vd,&vb); + + /* set up our packet->stream encoder */ + /* pick a random serial number; that way we can more likely build + chained streams just by concatenation */ + ogg_stream_init(&os, ll_rand()); + + /* Vorbis streams begin with three headers; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. The + third header holds the bitstream codebook. We merely need to + make the headers, then pass them to libvorbis one at a time; + libvorbis handles the additional Ogg bitstream constraints */ + + { + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); + ogg_stream_packetin(&os,&header); /* automatically placed in its own + page */ + ogg_stream_packetin(&os,&header_comm); + ogg_stream_packetin(&os,&header_code); + + /* We don't have to write out here, but doing so makes streaming + * much easier, so we do, flushing ALL pages. This ensures the actual + * audio data will start on a new page + */ + while(!eos){ + int result=ogg_stream_flush(&os,&og); + if(result==0)break; + outfile.write(og.header, og.header_len); + outfile.write(og.body, og.body_len); + } + + } + + + while(!eos) + { + long bytes_per_sample = bits_per_sample/8; + + long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ + + if (bytes==0) + { + /* end of file. this can be done implicitly in the mainline, + but it's easier to see here in non-clever fashion. + Tell the library we're at end of stream so that it can handle + the last frame and mark end of stream in the output properly */ + + vorbis_analysis_wrote(&vd,0); +// eos = 1; + + } + else + { + long i; + long samples; + int temp; + + data_left -= bytes; /* data to encode */ - - /* expose the buffer to submit data */ - float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER); - - i = 0; - samples = bytes / (num_channels * bytes_per_sample); - - if (num_channels == 2) - { - if (bytes_per_sample == 2) - { - /* uninterleave samples */ - for(i=0; i<samples ;i++) - { - temp = ((signed char *)readbuffer)[i*4+1]; /*Flawfinder: ignore*/ - temp += ((signed char *)readbuffer)[i*4+3]; /*Flawfinder: ignore*/ - temp <<= 8; - temp += readbuffer[i*4]; - temp += readbuffer[i*4+2]; - - buffer[0][i] = ((float)temp) / 65536.f; - } - } - else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") - { - /* uninterleave samples */ - for(i=0; i<samples ;i++) - { - temp = readbuffer[i*2+0]; - temp += readbuffer[i*2+1]; - temp -= 256; - buffer[0][i] = ((float)temp) / 256.f; - } - } - } - else if (num_channels == 1) - { - if (bytes_per_sample == 2) - { - for(i=0; i < samples ;i++) - { - temp = ((signed char*)readbuffer)[i*2+1]; - temp <<= 8; - temp += readbuffer[i*2]; - buffer[0][i] = ((float)temp) / 32768.f; - } - } - else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") - { - for(i=0; i < samples ;i++) - { - temp = readbuffer[i]; - temp -= 128; - buffer[0][i] = ((float)temp) / 128.f; - } - } - } - - /* tell the library how much we actually submitted */ - vorbis_analysis_wrote(&vd,i); - } - - /* vorbis does some data preanalysis, then divvies up blocks for - more involved (potentially parallel) processing. Get a single - block for encoding now */ - while(vorbis_analysis_blockout(&vd,&vb)==1) - { - - /* analysis */ - /* Do the main analysis, creating a packet */ - vorbis_analysis(&vb, NULL); - vorbis_bitrate_addblock(&vb); - - while(vorbis_bitrate_flushpacket(&vd, &op)) - { - - /* weld the packet into the bitstream */ - ogg_stream_packetin(&os,&op); - - /* write out pages (if any) */ - while(!eos) - { - result = ogg_stream_pageout(&os,&og); - - if(result==0) - break; - - outfile.write(og.header, og.header_len); - outfile.write(og.body, og.body_len); - - /* this could be set above, but for illustrative purposes, I do - it here (to show that vorbis does know where the stream ends) */ - - if(ogg_page_eos(&og)) - eos=1; - - } - } - } - } - - - - /* clean up and exit. vorbis_info_clear() must be called last */ - - ogg_stream_clear(&os); - vorbis_block_clear(&vb); - vorbis_dsp_clear(&vd); - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); - - /* ogg_page and ogg_packet structs always point to storage in - libvorbis. They're never freed or manipulated directly */ - -// fprintf(stderr,"Vorbis encoding: Done.\n"); - LL_INFOS() << "Vorbis encoding: Done." << LL_ENDL; - + + /* expose the buffer to submit data */ + float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER); + + i = 0; + samples = bytes / (num_channels * bytes_per_sample); + + if (num_channels == 2) + { + if (bytes_per_sample == 2) + { + /* uninterleave samples */ + for(i=0; i<samples ;i++) + { + temp = ((signed char *)readbuffer)[i*4+1]; /*Flawfinder: ignore*/ + temp += ((signed char *)readbuffer)[i*4+3]; /*Flawfinder: ignore*/ + temp <<= 8; + temp += readbuffer[i*4]; + temp += readbuffer[i*4+2]; + + buffer[0][i] = ((float)temp) / 65536.f; + } + } + else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") + { + /* uninterleave samples */ + for(i=0; i<samples ;i++) + { + temp = readbuffer[i*2+0]; + temp += readbuffer[i*2+1]; + temp -= 256; + buffer[0][i] = ((float)temp) / 256.f; + } + } + } + else if (num_channels == 1) + { + if (bytes_per_sample == 2) + { + for(i=0; i < samples ;i++) + { + temp = ((signed char*)readbuffer)[i*2+1]; + temp <<= 8; + temp += readbuffer[i*2]; + buffer[0][i] = ((float)temp) / 32768.f; + } + } + else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") + { + for(i=0; i < samples ;i++) + { + temp = readbuffer[i]; + temp -= 128; + buffer[0][i] = ((float)temp) / 128.f; + } + } + } + + /* tell the library how much we actually submitted */ + vorbis_analysis_wrote(&vd,i); + } + + /* vorbis does some data preanalysis, then divvies up blocks for + more involved (potentially parallel) processing. Get a single + block for encoding now */ + while(vorbis_analysis_blockout(&vd,&vb)==1) + { + + /* analysis */ + /* Do the main analysis, creating a packet */ + vorbis_analysis(&vb, NULL); + vorbis_bitrate_addblock(&vb); + + while(vorbis_bitrate_flushpacket(&vd, &op)) + { + + /* weld the packet into the bitstream */ + ogg_stream_packetin(&os,&op); + + /* write out pages (if any) */ + while(!eos) + { + result = ogg_stream_pageout(&os,&og); + + if(result==0) + break; + + outfile.write(og.header, og.header_len); + outfile.write(og.body, og.body_len); + + /* this could be set above, but for illustrative purposes, I do + it here (to show that vorbis does know where the stream ends) */ + + if(ogg_page_eos(&og)) + eos=1; + + } + } + } + } + + + + /* clean up and exit. vorbis_info_clear() must be called last */ + + ogg_stream_clear(&os); + vorbis_block_clear(&vb); + vorbis_dsp_clear(&vd); + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); + + /* ogg_page and ogg_packet structs always point to storage in + libvorbis. They're never freed or manipulated directly */ + +// fprintf(stderr,"Vorbis encoding: Done.\n"); + LL_INFOS() << "Vorbis encoding: Done." << LL_ENDL; + #endif - return(LLVORBISENC_NOERR); - + return(LLVORBISENC_NOERR); + } diff --git a/indra/llaudio/llvorbisencode.h b/indra/llaudio/llvorbisencode.h index 7372765075..34009fb8d8 100644 --- a/indra/llaudio/llvorbisencode.h +++ b/indra/llaudio/llvorbisencode.h @@ -1,25 +1,25 @@ -/** +/** * @file vorbisencode.h * @brief Vorbis encoding routine routine for Indra. * * $LicenseInfo:firstyear=2000&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$ */ @@ -46,7 +46,7 @@ const U32 LLVORBIS_CLIP_SAMPLE_RATE = 44100; const U32 LLVORBIS_CLIP_MAX_SAMPLES_PER_CHANNEL = (U32)(LLVORBIS_CLIP_MAX_TIME * LLVORBIS_CLIP_SAMPLE_RATE); const U32 LLVORBIS_CLIP_MAX_SAMPLES = LLVORBIS_CLIP_MAX_SAMPLES_PER_CHANNEL * LLVORBIS_CLIP_MAX_CHANNELS; const size_t LLVORBIS_CLIP_MAX_SAMPLE_DATA = LLVORBIS_CLIP_MAX_SAMPLES * 2; // 2 = 16-bit - + // Treat anything this long as a bad asset. A little fudge factor at the end: // Make that a lot of fudge factor. We're allowing 30 sec for now - 3x legal upload const size_t LLVORBIS_CLIP_REJECT_SAMPLES = LLVORBIS_CLIP_MAX_SAMPLES * 3; diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h index ec58f76f5f..57a14d902d 100644 --- a/indra/llaudio/llwindgen.h +++ b/indra/llaudio/llwindgen.h @@ -1,25 +1,25 @@ -/** +/** * @file windgen.h * @brief Templated wind noise generation * * $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$ */ @@ -33,137 +33,137 @@ template <class MIXBUFFERFORMAT_T> class LLWindGen { public: - LLWindGen(const U32 sample_rate = 44100) : - mTargetGain(0.f), - mTargetFreq(100.f), - mTargetPanGainR(0.5f), - mInputSamplingRate(sample_rate), - mSubSamples(2), - mFilterBandWidth(50.f), - mBuf0(0.0f), - mBuf1(0.0f), - mBuf2(0.0f), - mY0(0.0f), - mY1(0.0f), - mCurrentGain(0.f), - mCurrentFreq(100.f), - mCurrentPanGainR(0.5f), - mLastSample(0.f) - { - mSamplePeriod = (F32)mSubSamples / (F32)mInputSamplingRate; - mB2 = expf(-F_TWO_PI * mFilterBandWidth * mSamplePeriod); - } - - const U32 getInputSamplingRate() { return mInputSamplingRate; } - const F32 getNextSample(); - const F32 getClampedSample(bool clamp, F32 sample); - - // newbuffer = the buffer passed from the previous DSP unit. - // numsamples = length in samples-per-channel at this mix time. - // NOTE: generates L/R interleaved stereo - MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples) - { - MIXBUFFERFORMAT_T *cursamplep = newbuffer; - - // Filter coefficients - F32 a0 = 0.0f, b1 = 0.0f; - - // No need to clip at normal volumes - bool clip = mCurrentGain > 2.0f; - - bool interp_freq = false; - - //if the frequency isn't changing much, we don't need to interpolate in the inner loop - if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112)) - { - // calculate resonant filter coefficients - mCurrentFreq = mTargetFreq; - b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod)); - a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2)); - } - else - { - interp_freq = true; - } - - while (numsamples) - { - F32 next_sample; - - // Start with white noise - // This expression is fragile, rearrange it and it will break! - next_sample = getNextSample(); - - // Apply a pinking filter - // Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/ - mBuf0 = mBuf0 * 0.99765f + next_sample * 0.0990460f; - mBuf1 = mBuf1 * 0.96300f + next_sample * 0.2965164f; - mBuf2 = mBuf2 * 0.57000f + next_sample * 1.0526913f; - - next_sample = mBuf0 + mBuf1 + mBuf2 + next_sample * 0.1848f; - - if (interp_freq) - { - // calculate and interpolate resonant filter coefficients - mCurrentFreq = (0.999f * mCurrentFreq) + (0.001f * mTargetFreq); - b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod)); - a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2)); - } - - // Apply a resonant low-pass filter on the pink noise - next_sample = a0 * next_sample - b1 * mY0 - mB2 * mY1; - mY1 = mY0; - mY0 = next_sample; - - mCurrentGain = (0.999f * mCurrentGain) + (0.001f * mTargetGain); - mCurrentPanGainR = (0.999f * mCurrentPanGainR) + (0.001f * mTargetPanGainR); - - // For a 3dB pan law use: - // next_sample *= mCurrentGain * ((mCurrentPanGainR*(mCurrentPanGainR-1)*1.652+1.413); - next_sample *= mCurrentGain; - - // delta is used to interpolate between synthesized samples - F32 delta = (next_sample - mLastSample) / (F32)mSubSamples; - - // Fill the audio buffer, clipping if necessary - for (U8 i=mSubSamples; i && numsamples; --i, --numsamples) - { - mLastSample = mLastSample + delta; - MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR); - MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right); - - *cursamplep = sample_left; - ++cursamplep; - *cursamplep = sample_right; - ++cursamplep; - } - } - - return newbuffer; - } - + LLWindGen(const U32 sample_rate = 44100) : + mTargetGain(0.f), + mTargetFreq(100.f), + mTargetPanGainR(0.5f), + mInputSamplingRate(sample_rate), + mSubSamples(2), + mFilterBandWidth(50.f), + mBuf0(0.0f), + mBuf1(0.0f), + mBuf2(0.0f), + mY0(0.0f), + mY1(0.0f), + mCurrentGain(0.f), + mCurrentFreq(100.f), + mCurrentPanGainR(0.5f), + mLastSample(0.f) + { + mSamplePeriod = (F32)mSubSamples / (F32)mInputSamplingRate; + mB2 = expf(-F_TWO_PI * mFilterBandWidth * mSamplePeriod); + } + + const U32 getInputSamplingRate() { return mInputSamplingRate; } + const F32 getNextSample(); + const F32 getClampedSample(bool clamp, F32 sample); + + // newbuffer = the buffer passed from the previous DSP unit. + // numsamples = length in samples-per-channel at this mix time. + // NOTE: generates L/R interleaved stereo + MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples) + { + MIXBUFFERFORMAT_T *cursamplep = newbuffer; + + // Filter coefficients + F32 a0 = 0.0f, b1 = 0.0f; + + // No need to clip at normal volumes + bool clip = mCurrentGain > 2.0f; + + bool interp_freq = false; + + //if the frequency isn't changing much, we don't need to interpolate in the inner loop + if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112)) + { + // calculate resonant filter coefficients + mCurrentFreq = mTargetFreq; + b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod)); + a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2)); + } + else + { + interp_freq = true; + } + + while (numsamples) + { + F32 next_sample; + + // Start with white noise + // This expression is fragile, rearrange it and it will break! + next_sample = getNextSample(); + + // Apply a pinking filter + // Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/ + mBuf0 = mBuf0 * 0.99765f + next_sample * 0.0990460f; + mBuf1 = mBuf1 * 0.96300f + next_sample * 0.2965164f; + mBuf2 = mBuf2 * 0.57000f + next_sample * 1.0526913f; + + next_sample = mBuf0 + mBuf1 + mBuf2 + next_sample * 0.1848f; + + if (interp_freq) + { + // calculate and interpolate resonant filter coefficients + mCurrentFreq = (0.999f * mCurrentFreq) + (0.001f * mTargetFreq); + b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod)); + a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2)); + } + + // Apply a resonant low-pass filter on the pink noise + next_sample = a0 * next_sample - b1 * mY0 - mB2 * mY1; + mY1 = mY0; + mY0 = next_sample; + + mCurrentGain = (0.999f * mCurrentGain) + (0.001f * mTargetGain); + mCurrentPanGainR = (0.999f * mCurrentPanGainR) + (0.001f * mTargetPanGainR); + + // For a 3dB pan law use: + // next_sample *= mCurrentGain * ((mCurrentPanGainR*(mCurrentPanGainR-1)*1.652+1.413); + next_sample *= mCurrentGain; + + // delta is used to interpolate between synthesized samples + F32 delta = (next_sample - mLastSample) / (F32)mSubSamples; + + // Fill the audio buffer, clipping if necessary + for (U8 i=mSubSamples; i && numsamples; --i, --numsamples) + { + mLastSample = mLastSample + delta; + MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR); + MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right); + + *cursamplep = sample_left; + ++cursamplep; + *cursamplep = sample_right; + ++cursamplep; + } + } + + return newbuffer; + } + public: - F32 mTargetGain; - F32 mTargetFreq; - F32 mTargetPanGainR; - + F32 mTargetGain; + F32 mTargetFreq; + F32 mTargetPanGainR; + private: - U32 mInputSamplingRate; - U8 mSubSamples; - F32 mSamplePeriod; - F32 mFilterBandWidth; - F32 mB2; - - F32 mBuf0; - F32 mBuf1; - F32 mBuf2; - F32 mY0; - F32 mY1; - - F32 mCurrentGain; - F32 mCurrentFreq; - F32 mCurrentPanGainR; - F32 mLastSample; + U32 mInputSamplingRate; + U8 mSubSamples; + F32 mSamplePeriod; + F32 mFilterBandWidth; + F32 mB2; + + F32 mBuf0; + F32 mBuf1; + F32 mBuf2; + F32 mY0; + F32 mY1; + + F32 mCurrentGain; + F32 mCurrentFreq; + F32 mCurrentPanGainR; + 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); } |