audioengine_fmod.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 
00035 #include "audioengine_fmod.h"
00036 
00037 #if LL_FMOD
00038 
00039 #include "listener_fmod.h"
00040 
00041 #include "llerror.h"
00042 #include "llmath.h"
00043 #include "llrand.h"
00044 
00045 #include "fmod.h"
00046 #include "fmod_errors.h"
00047 #include "lldir.h"
00048 #include "llapr.h"
00049 
00050 #include "sound_ids.h"
00051 
00052 
00053 void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata);
00054 FSOUND_DSPUNIT *gWindDSP = NULL;
00055 
00056 // These globals for the wind filter.  Blech!
00057 F64 gbuf0 = 0.0;
00058 F64 gbuf1 = 0.0;
00059 F64 gbuf2 = 0.0;
00060 F64 gbuf3 = 0.0;
00061 F64 gbuf4 = 0.0;
00062 F64 gbuf5 = 0.0;
00063 F64 gY0 = 0.0;
00064 F64 gY1 = 0.0;
00065 
00066 F32 gTargetGain = 0.f;
00067 F32 gCurrentGain = 0.f;
00068 F32 gTargetFreq = 100.f;
00069 F32 gCurrentFreq = 100.f;
00070 F32 gTargetPanGainR = 0.5f;
00071 F32 gCurrentPanGainR = 0.5f;
00072 
00073 
00074 // Safe strcpy
00075 #if LL_WINDOWS || LL_LINUX
00076 static size_t strlcpy( char* dest, const char* src, size_t dst_size )
00077 {
00078         size_t source_len = 0;
00079         size_t min_len = 0;
00080         if( dst_size > 0 )
00081         {
00082                 if( src )
00083                 {
00084                         source_len = strlen(src);       /*Flawfinder: ignore*/
00085                         min_len = llmin( dst_size - 1, source_len );
00086                         memcpy(dest, src, min_len);     /*Flawfinder: ignore*/  
00087                 }
00088                 dest[min_len] = '\0';
00089         }
00090         return source_len;
00091 }
00092 #else
00093 // apple ships with the non-standard strlcpy in /usr/include/string.h:
00094 // size_t strlcpy(char *, const char *, size_t);
00095 #endif
00096 
00097 
00098 LLAudioEngine_FMOD::LLAudioEngine_FMOD()
00099 {
00100         mInited = FALSE;
00101         mCurrentInternetStreamp = NULL;
00102         mInternetStreamChannel = -1;
00103 }
00104 
00105 
00106 LLAudioEngine_FMOD::~LLAudioEngine_FMOD()
00107 {
00108 }
00109 
00110 
00111 BOOL LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata)
00112 {
00113         mFadeIn = -10000;
00114 
00115         LLAudioEngine::init(num_channels, userdata);
00116 
00117         // Reserve one extra channel for the http stream.
00118         if (!FSOUND_SetMinHardwareChannels(num_channels + 1))
00119         {
00120                 LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00121         }
00122 
00123         LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL;
00124 
00125         F32 version = FSOUND_GetVersion();
00126         if (version < FMOD_VERSION)
00127         {
00128                 LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
00129                         << ")!  You should be using FMOD " << FMOD_VERSION << LL_ENDL;
00130                 //return FALSE;
00131         }
00132 
00133         U32 fmod_flags = 0x0;
00134 
00135 #if LL_WINDOWS
00136         // Windows needs to know which window is frontmost.
00137         // This must be called before FSOUND_Init() per the FMOD docs.
00138         // This could be used to let FMOD handle muting when we lose focus,
00139         // but we don't actually want to do that because we want to distinguish
00140         // between minimized and not-focused states.
00141         if (!FSOUND_SetHWND(userdata))
00142         {
00143                 LL_WARNS("AppInit") << "Error setting FMOD window: "
00144                         << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00145                 return FALSE;
00146         }
00147         // Play audio when we don't have focus.
00148         // (For example, IM client on top of us.)
00149         // This means we also try to play audio when minimized,
00150         // so we manually handle muting in that case. JC
00151         fmod_flags |= FSOUND_INIT_GLOBALFOCUS;
00152 #endif
00153 
00154 #if LL_LINUX
00155         // initialize the FMOD engine
00156 
00157         // This is a hack to use only FMOD's basic FPU mixer
00158         // when the LL_VALGRIND environmental variable is set,
00159         // otherwise valgrind will fall over on FMOD's MMX detection
00160         if (getenv("LL_VALGRIND"))              /*Flawfinder: ignore*/
00161         {
00162                 LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL;
00163                 FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU);
00164         }
00165 
00166         // If we don't set an output method, Linux FMOD always
00167         // decides on OSS and fails otherwise.  So we'll manually
00168         // try ESD, then OSS, then ALSA.
00169         // Why this order?  See SL-13250, but in short, OSS emulated
00170         // on top of ALSA is ironically more reliable than raw ALSA.
00171         // Ack, and ESD has more reliable failure modes - but has worse
00172         // latency - than all of them, so wins for now.
00173         BOOL audio_ok = FALSE;
00174 
00175         if (!audio_ok)
00176                 if (NULL == getenv("LL_BAD_ESD")) /*Flawfinder: ignore*/
00177                 {
00178                         LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
00179                         if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) &&
00180                            FSOUND_Init(44100, num_channels, fmod_flags))
00181                         {
00182                                 LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY"
00183                                         << LL_ENDL;
00184                                 audio_ok = TRUE;
00185                         } else {
00186                                 LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: "
00187                                         << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00188                         }
00189                 } else {
00190                         LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
00191                 }
00192 
00193         if (!audio_ok)
00194                 if (NULL == getenv("LL_BAD_OSS"))        /*Flawfinder: ignore*/
00195                 {
00196                         LL_DEBUGS("AppInit") << "Trying OSS audio output..."    << LL_ENDL;
00197                         if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) &&
00198                            FSOUND_Init(44100, num_channels, fmod_flags))
00199                         {
00200                                 LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
00201                                 audio_ok = TRUE;
00202                         } else {
00203                                 LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: "
00204                                         << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00205                         }
00206                 } else {
00207                         LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
00208                 }
00209 
00210         if (!audio_ok)
00211                 if (NULL == getenv("LL_BAD_ALSA"))              /*Flawfinder: ignore*/
00212                 {
00213                         LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
00214                         if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) &&
00215                            FSOUND_Init(44100, num_channels, fmod_flags))
00216                         {
00217                                 LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
00218                                 audio_ok = TRUE;
00219                         } else {
00220                                 LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: "
00221                                         << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00222                         }
00223                 } else {
00224                         LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
00225                 }
00226 
00227         if (!audio_ok)
00228         {
00229                 LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
00230                 return FALSE;
00231         }
00232 
00233         // On Linux, FMOD causes a SIGPIPE for some netstream error
00234         // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
00235         // NOW FIXED in FMOD 3.x since 2006-10-01.
00236         //signal(SIGPIPE, SIG_IGN);
00237 
00238         // We're interested in logging which output method we
00239         // ended up with, for QA purposes.
00240         switch (FSOUND_GetOutput())
00241         {
00242         case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
00243         case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
00244         case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
00245         case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
00246         default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
00247         };
00248 
00249 #else // LL_LINUX
00250 
00251         // initialize the FMOD engine
00252         if (!FSOUND_Init(44100, num_channels, fmod_flags))
00253         {
00254                 LL_WARNS("AppInit") << "Error initializing FMOD: "
00255                         << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
00256                 return FALSE;
00257         }
00258         
00259 #endif
00260 
00261         initInternetStream();
00262 
00263         LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL;
00264 
00265         mInited = TRUE;
00266 
00267         return TRUE;
00268 }
00269 
00270 
00271 void LLAudioEngine_FMOD::idle(F32 max_decode_time)
00272 {
00273         LLAudioEngine::idle(max_decode_time);
00274 
00275         updateInternetStream();
00276 }
00277 
00278 
00279 void LLAudioEngine_FMOD::allocateListener(void)
00280 {       
00281         mListenerp = (LLListener *) new LLListener_FMOD();
00282         if (!mListenerp)
00283         {
00284                 llwarns << "Listener creation failed" << llendl;
00285         }
00286 }
00287 
00288 
00289 void LLAudioEngine_FMOD::shutdown()
00290 {
00291         if (gWindDSP)
00292         {
00293                 FSOUND_DSP_SetActive(gWindDSP,FALSE);
00294                 FSOUND_DSP_Free(gWindDSP);
00295         }
00296 
00297         stopInternetStream();
00298 
00299         LLAudioEngine::shutdown();
00300         
00301         llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl;
00302         FSOUND_Close();
00303         llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl;
00304 
00305         delete mListenerp;
00306         mListenerp = NULL;
00307 }
00308 
00309 
00310 LLAudioBuffer *LLAudioEngine_FMOD::createBuffer()
00311 {
00312         return new LLAudioBufferFMOD();
00313 }
00314 
00315 
00316 LLAudioChannel *LLAudioEngine_FMOD::createChannel()
00317 {
00318         return new LLAudioChannelFMOD();
00319 }
00320 
00321 
00322 void LLAudioEngine_FMOD::initWind()
00323 {
00324         if (!gWindDSP)
00325         {
00326                 gWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, NULL);
00327         }
00328         if (gWindDSP)
00329         {
00330                 FSOUND_DSP_SetActive(gWindDSP, TRUE);
00331         }
00332         mNextWindUpdate = 0.0;
00333 }
00334 
00335 
00336 void LLAudioEngine_FMOD::cleanupWind()
00337 {
00338         if (gWindDSP)
00339         {
00340                 FSOUND_DSP_SetActive(gWindDSP, FALSE);
00341                 FSOUND_DSP_Free(gWindDSP);
00342                 gWindDSP = NULL;
00343         }
00344 }
00345 
00346 
00347 //-----------------------------------------------------------------------
00348 void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
00349 {
00350         LLVector3 wind_pos;
00351         F64 pitch;
00352         F64 center_freq;
00353 
00354         if (!mEnableWind)
00355         {
00356                 return;
00357         }
00358         
00359         if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
00360         {
00361                 
00362                 // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
00363                 // need to convert this to the conventional orientation DS3D and OpenAL use
00364                 // where +X = right, +Y = up, +Z = backwards
00365 
00366                 wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
00367 
00368                 // cerr << "Wind update" << endl;
00369 
00370                 pitch = 1.0 + mapWindVecToPitch(wind_vec);
00371                 center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
00372                 
00373                 gTargetFreq = (F32)center_freq;
00374                 gTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
00375                 gTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
00376         }
00377 }
00378 
00379 /*
00380 //-----------------------------------------------------------------------
00381 void LLAudioEngine_FMOD::setSourceMinDistance(U16 source_num, F64 distance)
00382 {
00383         if (!mInited)
00384         {
00385                 return;
00386         }
00387         if (mBuffer[source_num])
00388         {
00389                 mMinDistance[source_num] = (F32) distance;
00390                 if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
00391                 {
00392                         llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00393                 }
00394         }
00395 }
00396 
00397 //-----------------------------------------------------------------------
00398 void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance)
00399 {
00400         if (!mInited)
00401         {
00402                 return;
00403         }
00404         if (mBuffer[source_num])
00405         {
00406                 mMaxDistance[source_num] = (F32) distance;
00407                 if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
00408                 {
00409                         llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00410                 }
00411         }
00412 }
00413 
00414 //-----------------------------------------------------------------------
00415 void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist)
00416 {
00417         *volume = 0;
00418         *freq = 0;
00419         *inside = 0;
00420         *outside = 0;
00421         *orient = LLVector3::zero;
00422         *out_volume = 0;
00423         *min_dist = 0.f;
00424         *max_dist = 0.f;
00425 }
00426 
00427 */
00428 
00429 
00430 //-----------------------------------------------------------------------
00431 void LLAudioEngine_FMOD::setInternalGain(F32 gain)
00432 {
00433         if (!mInited)
00434         {
00435                 return;
00436         }
00437 
00438         gain = llclamp( gain, 0.0f, 1.0f );
00439         FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) );
00440 
00441         if ( mInternetStreamChannel != -1 )
00442         {
00443                 F32 clamp_internet_stream_gain = llclamp( mInternetStreamGain, 0.0f, 1.0f );
00444                 FSOUND_SetVolumeAbsolute( mInternetStreamChannel, llround( 255.0f * clamp_internet_stream_gain ) );
00445         }
00446 }
00447 
00448 //
00449 // LLAudioChannelFMOD implementation
00450 //
00451 
00452 LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0)
00453 {
00454 }
00455 
00456 
00457 LLAudioChannelFMOD::~LLAudioChannelFMOD()
00458 {
00459         cleanup();
00460 }
00461 
00462 
00463 BOOL LLAudioChannelFMOD::updateBuffer()
00464 {
00465         if (LLAudioChannel::updateBuffer())
00466         {
00467                 // Base class update returned TRUE, which means that we need to actually
00468                 // set up the channel for a different buffer.
00469 
00470                 LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer();
00471 
00472                 // Grab the FMOD sample associated with the buffer
00473                 FSOUND_SAMPLE *samplep = bufferp->getSample();
00474                 if (!samplep)
00475                 {
00476                         // This is bad, there should ALWAYS be a sample associated with a legit
00477                         // buffer.
00478                         llerrs << "No FMOD sample!" << llendl;
00479                         return FALSE;
00480                 }
00481 
00482 
00483                 // Actually play the sound.  Start it off paused so we can do all the necessary
00484                 // setup.
00485                 mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), TRUE);
00486 
00487                 //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
00488         }
00489 
00490         // If we have a source for the channel, we need to update its gain.
00491         if (mCurrentSourcep)
00492         {
00493                 // SJB: warnings can spam and hurt framerate, disabling
00494                 if (!FSOUND_SetVolume(mChannelID, llround(mCurrentSourcep->getGain() * 255.0f)))
00495                 {
00496 //                      llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00497                 }
00498                 
00499                 if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
00500                 {
00501 //                      llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID()
00502 //                                      << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
00503 //                      llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00504                 }
00505         }
00506 
00507         return TRUE;
00508 }
00509 
00510 
00511 void LLAudioChannelFMOD::update3DPosition()
00512 {
00513         if (!mChannelID)
00514         {
00515                 // We're not actually a live channel (i.e., we're not playing back anything)
00516                 return;
00517         }
00518 
00519         LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp;
00520         if (!bufferp)
00521         {
00522                 // We don't have a buffer associated with us (should really have been picked up
00523                 // by the above if.
00524                 return;
00525         }
00526 
00527         if (mCurrentSourcep->isAmbient())
00528         {
00529                 // Ambient sound, don't need to do any positional updates.
00530                 bufferp->set3DMode(FALSE);
00531         }
00532         else
00533         {
00534                 // Localized sound.  Update the position and velocity of the sound.
00535                 bufferp->set3DMode(TRUE);
00536 
00537                 LLVector3 float_pos;
00538                 float_pos.setVec(mCurrentSourcep->getPositionGlobal());
00539                 if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV))
00540                 {
00541                         llwarns << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00542                 }
00543         }
00544 }
00545 
00546 
00547 void LLAudioChannelFMOD::updateLoop()
00548 {
00549         if (!mChannelID)
00550         {
00551                 // May want to clear up the loop/sample counters.
00552                 return;
00553         }
00554 
00555         //
00556         // Hack:  We keep track of whether we looped or not by seeing when the sign of the last sample
00557         // flips.  This is pretty crappy.
00558         //
00559         U32 cur_pos = FSOUND_GetCurrentPosition(mChannelID);
00560         if (cur_pos < (U32)mLastSamplePos)
00561         {
00562                 mLoopedThisFrame = TRUE;
00563         }
00564         mLastSamplePos = cur_pos;
00565 }
00566 
00567 
00568 void LLAudioChannelFMOD::cleanup()
00569 {
00570         if (!mChannelID)
00571         {
00572                 //llinfos << "Aborting cleanup with no channelID." << llendl;
00573                 return;
00574         }
00575 
00576         //llinfos << "Cleaning up channel: " << mChannelID << llendl;
00577         if (!FSOUND_StopSound(mChannelID))
00578         {
00579                 llwarns << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00580         }
00581 
00582         mCurrentBufferp = NULL;
00583         mChannelID = 0;
00584 }
00585 
00586 
00587 void LLAudioChannelFMOD::play()
00588 {
00589         if (!mChannelID)
00590         {
00591                 llwarns << "Playing without a channelID, aborting" << llendl;
00592                 return;
00593         }
00594 
00595         if (!FSOUND_SetPaused(mChannelID, FALSE))
00596         {
00597                 llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00598         }
00599         getSource()->setPlayedOnce(TRUE);
00600 }
00601 
00602 
00603 void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp)
00604 {
00605         LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp;
00606         if (!(fmod_channelp->mChannelID && mChannelID))
00607         {
00608                 // Don't have channels allocated to both the master and the slave
00609                 return;
00610         }
00611 
00612         U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength();
00613         // Try to match the position of our sync master
00614         if (!FSOUND_SetCurrentPosition(mChannelID, position))
00615         {
00616                 llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl;
00617         }
00618 
00619         // Start us playing
00620         play();
00621 }
00622 
00623 
00624 BOOL LLAudioChannelFMOD::isPlaying()
00625 {
00626         if (!mChannelID)
00627         {
00628                 return FALSE;
00629         }
00630 
00631         return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID));
00632 }
00633 
00634 
00635 
00636 //
00637 // LLAudioBufferFMOD implementation
00638 //
00639 
00640 
00641 LLAudioBufferFMOD::LLAudioBufferFMOD()
00642 {
00643         mSamplep = NULL;
00644 }
00645 
00646 
00647 LLAudioBufferFMOD::~LLAudioBufferFMOD()
00648 {
00649         if (mSamplep)
00650         {
00651                 // Clean up the associated FMOD sample if it exists.
00652                 FSOUND_Sample_Free(mSamplep);
00653                 mSamplep = NULL;
00654         }
00655 }
00656 
00657 
00658 BOOL LLAudioBufferFMOD::loadWAV(const char *filename)
00659 {
00660         // Try to open a wav file from disk.  This will eventually go away, as we don't
00661         // really want to block doing this.
00662         if (filename == NULL)
00663         {
00664                 // invalid filename, abort.
00665                 return FALSE;
00666         }
00667 
00668         S32 file_size = 0;
00669         apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RPB, &file_size);
00670         if (!apr_file)
00671         {
00672                 // File not found, abort.
00673                 return FALSE;
00674         }
00675         apr_file_close(apr_file);
00676 
00677         if (mSamplep)
00678         {
00679                 // If there's already something loaded in this buffer, clean it up.
00680                 FSOUND_Sample_Free(mSamplep);
00681                 mSamplep = NULL;
00682         }
00683 
00684         // Load up the wav file into an fmod sample
00685 #if LL_WINDOWS
00686         // MikeS. - Loading the sound file manually and then handing it over to FMOD,
00687         //      since FMOD uses posix IO internally,
00688         // which doesn't work with unicode file paths.
00689         LLFILE* sound_file = LLFile::fopen(filename,"rb");      /* Flawfinder: ignore */
00690         if (sound_file)
00691         {
00692                 fseek(sound_file,0,SEEK_END);
00693                 U32     file_length = ftell(sound_file);        //Find the length of the file by seeking to the end and getting the offset
00694                 size_t  read_count;
00695                 fseek(sound_file,0,SEEK_SET);   //Seek back to the beginning
00696                 char*   buffer = new char[file_length];
00697                 llassert(buffer);
00698                 read_count = fread((void*)buffer,file_length,1,sound_file);//Load it..
00699                 if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size...
00700                         unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY;
00701                                                                         //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL;
00702                         mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length);
00703                 }
00704                 delete[] buffer;
00705                 fclose(sound_file);
00706         }
00707 #else
00708         mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename, FSOUND_LOOP_NORMAL, 0, 0);
00709 #endif
00710 
00711         if (!mSamplep)
00712         {
00713                 // We failed to load the file for some reason.
00714                 llwarns << "Could not load data '" << filename << "': "
00715                                 << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00716 
00717                 //
00718                 // If we EVER want to load wav files provided by end users, we need
00719                 // to rethink this!
00720                 //
00721                 // file is probably corrupt - remove it.
00722                 LLFile::remove(filename);
00723                 return FALSE;
00724         }
00725 
00726         // Everything went well, return TRUE
00727         return TRUE;
00728 }
00729 
00730 
00731 U32 LLAudioBufferFMOD::getLength()
00732 {
00733         if (!mSamplep)
00734         {
00735                 return 0;
00736         }
00737 
00738         return FSOUND_Sample_GetLength(mSamplep);
00739 }
00740 
00741 
00742 void LLAudioBufferFMOD::set3DMode(BOOL use3d)
00743 {
00744         U16 current_mode = FSOUND_Sample_GetMode(mSamplep);
00745         
00746         if (use3d)
00747         {
00748                 if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D))))
00749                 {
00750                         llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00751                 }
00752         }
00753         else
00754         {
00755                 if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D))
00756                 {
00757                         llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00758                 }
00759         }
00760 }
00761 
00762 
00763 
00764 //---------------------------------------------------------------------------
00765 // Internet Streaming
00766 //---------------------------------------------------------------------------
00767 void LLAudioEngine_FMOD::initInternetStream()
00768 {
00769         // Number of milliseconds of audio to buffer for the audio card.
00770         // Must be larger than the usual Second Life frame stutter time.
00771     FSOUND_Stream_SetBufferSize(200);
00772 
00773         // Here's where we set the size of the network buffer and some buffering 
00774         // parameters.  In this case we want a network buffer of 16k, we want it 
00775         // to prebuffer 40% of that when we first connect, and we want it 
00776         // to rebuffer 80% of that whenever we encounter a buffer underrun.
00777 
00778         // Leave the net buffer properties at the default.
00779         //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
00780         mInternetStreamURL[0] = 0;
00781 }
00782 
00783 
00784 void LLAudioEngine_FMOD::startInternetStream(const char* url)
00785 {
00786         if (!mInited)
00787         {
00788                 llwarns << "startInternetStream before audio initialized" << llendl;
00789                 return;
00790         }
00791 
00792         // "stop" stream but don't clear url, etc. in calse url == mInternetStreamURL
00793         stopInternetStream();
00794         if (url)
00795         {
00796                 llinfos << "Starting internet stream: " << url << llendl;
00797                 mCurrentInternetStreamp = new LLAudioStreamFMOD(url);
00798                 strlcpy(mInternetStreamURL, url, 1024);
00799         }
00800         else
00801         {
00802                 llinfos << "Set internet stream to null" << llendl;
00803                 mInternetStreamURL[0] = 0;
00804         }
00805 }
00806 
00807 
00808 signed char F_CALLBACKAPI LLAudioEngine_FMOD::callbackMetaData(char *name, char *value, void *userdata)
00809 {
00810         /*
00811         LLAudioEngine_FMOD* self = (LLAudioEngine_FMOD*)userdata;
00812 
00813     if (!strcmp("ARTIST", name))
00814     {
00815         strlcpy(self->mInternetStreamArtist, value, 256);
00816         self->mInternetStreamNewMetaData = TRUE;
00817         return TRUE;
00818     }
00819 
00820     if (!strcmp("TITLE", name))
00821     {
00822         strlcpy(self->mInternetStreamTitle, value, 256);
00823         self->mInternetStreamNewMetaData = TRUE;
00824         return TRUE;
00825     }
00826         */
00827 
00828     return TRUE;
00829 }
00830 
00831 
00832 void LLAudioEngine_FMOD::updateInternetStream()
00833 {
00834         // Kill dead internet streams, if possible
00835         std::list<LLAudioStreamFMOD *>::iterator iter;
00836         for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
00837         {
00838                 LLAudioStreamFMOD *streamp = *iter;
00839                 if (streamp->stopStream())
00840                 {
00841                         llinfos << "Closed dead stream" << llendl;
00842                         delete streamp;
00843                         mDeadStreams.erase(iter++);
00844                 }
00845                 else
00846                 {
00847                         iter++;
00848                 }
00849         }
00850 
00851         // Don't do anything if there are no streams playing
00852         if (!mCurrentInternetStreamp)
00853         {
00854                 return;
00855         }
00856 
00857     int open_state = mCurrentInternetStreamp->getOpenState();
00858 
00859         if (!open_state)
00860         {
00861                 // Stream is live
00862 
00863 
00864                 // start the stream if it's ready
00865                 if (mInternetStreamChannel < 0)
00866                 {
00867                         mInternetStreamChannel = mCurrentInternetStreamp->startStream();
00868 
00869                         if (mInternetStreamChannel != -1)
00870                         {
00871                                 // Reset volume to previously set volume
00872                                 setInternetStreamGain(mInternetStreamGain);
00873                                 FSOUND_SetPaused(mInternetStreamChannel, FALSE);
00874                                 //FSOUND_Stream_Net_SetMetadataCallback(mInternetStream, callbackMetaData, this);
00875                         }
00876                 }
00877         }
00878                 
00879         switch(open_state)
00880         {
00881         default:
00882         case 0:
00883                 // success
00884                 break;
00885         case -1:
00886                 // stream handle is invalid
00887                 llwarns << "InternetStream - invalid handle" << llendl;
00888                 stopInternetStream();
00889                 return;
00890         case -2:
00891                 // opening
00892                 //strlcpy(mInternetStreamArtist, "Opening", 256);
00893                 break;
00894         case -3:
00895                 // failed to open, file not found, perhaps
00896                 llwarns << "InternetSteam - failed to open" << llendl;
00897                 stopInternetStream();
00898                 return;
00899         case -4:
00900                 // connecting
00901                 //strlcpy(mInternetStreamArtist, "Connecting", 256);
00902                 break;
00903         case -5:
00904                 // buffering
00905                 //strlcpy(mInternetStreamArtist, "Buffering", 256);
00906                 break;
00907         }
00908 
00909 }
00910 
00911 void LLAudioEngine_FMOD::stopInternetStream()
00912 {
00913         if (mInternetStreamChannel != -1)
00914         {
00915                 FSOUND_SetPaused(mInternetStreamChannel, TRUE);
00916                 FSOUND_SetPriority(mInternetStreamChannel, 0);
00917                 mInternetStreamChannel = -1;
00918         }
00919 
00920         if (mCurrentInternetStreamp)
00921         {
00922                 llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
00923                 if (mCurrentInternetStreamp->stopStream())
00924                 {
00925                         delete mCurrentInternetStreamp;
00926                 }
00927                 else
00928                 {
00929                         llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
00930                         mDeadStreams.push_back(mCurrentInternetStreamp);
00931                 }
00932                 mCurrentInternetStreamp = NULL;
00933                 //mInternetStreamURL[0] = 0;
00934         }
00935 }
00936 
00937 void LLAudioEngine_FMOD::pauseInternetStream(int pause)
00938 {
00939         if (pause < 0)
00940         {
00941                 pause = mCurrentInternetStreamp ? 1 : 0;
00942         }
00943 
00944         if (pause)
00945         {
00946                 if (mCurrentInternetStreamp)
00947                 {
00948                         stopInternetStream();
00949                 }
00950         }
00951         else
00952         {
00953                 startInternetStream(mInternetStreamURL);
00954         }
00955 }
00956 
00957 
00958 // A stream is "playing" if it has been requested to start.  That
00959 // doesn't necessarily mean audio is coming out of the speakers.
00960 int LLAudioEngine_FMOD::isInternetStreamPlaying()
00961 {
00962         if (mCurrentInternetStreamp)
00963         {
00964                 return 1; // Active and playing
00965         }
00966         else if (mInternetStreamURL[0])
00967         {
00968                 return 2; // "Paused"
00969         }
00970         else
00971         {
00972                 return 0;
00973         }
00974 }
00975 
00976 
00977 void LLAudioEngine_FMOD::getInternetStreamInfo(char* artist_out, char* title_out)
00978 {
00979         //strlcpy(artist_out, mInternetStreamArtist, 256);
00980         //strlcpy(title_out, mInternetStreamTitle, 256);
00981 }
00982 
00983 
00984 void LLAudioEngine_FMOD::setInternetStreamGain(F32 vol)
00985 {
00986         LLAudioEngine::setInternetStreamGain(vol);
00987         if (mInternetStreamChannel != -1)
00988         {
00989                 vol = llclamp(vol, 0.f, 1.f);
00990                 int vol_int = llround(vol * 255.f);
00991                 FSOUND_SetVolumeAbsolute(mInternetStreamChannel, vol_int);
00992         }
00993 }
00994 
00995 
00996 const char* LLAudioEngine_FMOD::getInternetStreamURL()
00997 {
00998         return mInternetStreamURL;
00999 }
01000 
01001 
01002 LLAudioStreamFMOD::LLAudioStreamFMOD(const char *url) :
01003         mInternetStream(NULL),
01004         mReady(FALSE)
01005 {
01006         mInternetStreamURL[0] = 0;
01007         strlcpy(mInternetStreamURL, url, 1024);
01008         mInternetStream = FSOUND_Stream_Open(url, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0);
01009         if (!mInternetStream)
01010         {
01011                 llwarns << "Couldn't open fmod stream, error "
01012                         << FMOD_ErrorString(FSOUND_GetError())
01013                         << llendl;
01014                 mReady = FALSE;
01015                 return;
01016         }
01017 
01018         mReady = TRUE;
01019 }
01020 
01021 int LLAudioStreamFMOD::startStream()
01022 {
01023         // We need a live and opened stream before we try and play it.
01024         if (!mInternetStream || getOpenState())
01025         {
01026                 llwarns << "No internet stream to start playing!" << llendl;
01027                 return -1;
01028         }
01029 
01030         // Make sure the stream is set to 2D mode.
01031         FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D);
01032 
01033         return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, TRUE);
01034 }
01035 
01036 BOOL LLAudioStreamFMOD::stopStream()
01037 {
01038         if (mInternetStream)
01039         {
01040                 int read_percent = 0;
01041                 int status = 0;
01042                 int bitrate = 0;
01043                 unsigned int flags = 0x0;
01044                 FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags);
01045 
01046                 BOOL close = TRUE;
01047                 switch (status)
01048                 {
01049                 case FSOUND_STREAM_NET_CONNECTING:
01050                         close = FALSE;
01051                         break;
01052                 case FSOUND_STREAM_NET_NOTCONNECTED:
01053                 case FSOUND_STREAM_NET_BUFFERING:
01054                 case FSOUND_STREAM_NET_READY:
01055                 case FSOUND_STREAM_NET_ERROR:
01056                 default:
01057                         close = TRUE;
01058                 }
01059 
01060                 if (close)
01061                 {
01062                         FSOUND_Stream_Close(mInternetStream);
01063                         mInternetStream = NULL;
01064                         return TRUE;
01065                 }
01066                 else
01067                 {
01068                         return FALSE;
01069                 }
01070         }
01071         else
01072         {
01073                 return TRUE;
01074         }
01075 }
01076 
01077 int LLAudioStreamFMOD::getOpenState()
01078 {
01079         int open_state = FSOUND_Stream_GetOpenState(mInternetStream);
01080         return open_state;
01081 }
01082 
01083 /* This determines the format of the mixbuffer being passed in. change if you want to support int32 or float32 */
01084 #if LL_DARWIN
01085         #define MIXBUFFERFORMAT S32
01086 #else
01087         #define MIXBUFFERFORMAT S16
01088 #endif
01089 
01090 inline MIXBUFFERFORMAT clipSample(MIXBUFFERFORMAT sample, MIXBUFFERFORMAT min, MIXBUFFERFORMAT max)
01091 {
01092         if (sample > max)
01093                 sample = max;
01094         else if (sample < min)
01095                 sample = min;
01096         
01097         return sample;
01098 }
01099 
01100 void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void*)
01101 {
01102 // originalbuffer = fsounds original mixbuffer.
01103 // newbuffer = the buffer passed from the previous DSP unit.
01104 // length = length in samples at this mix time.
01105 // param = user parameter passed through in FSOUND_DSP_Create.
01106 //
01107 // modify the buffer in some fashion
01108 
01109         U8 *cursamplep = (U8*)newbuffer;
01110         U8   wordsize = 2;
01111 
01112 #if LL_DARWIN
01113         wordsize = sizeof(MIXBUFFERFORMAT);
01114 #else
01115     int         mixertype = FSOUND_GetMixer();
01116     if (mixertype == FSOUND_MIXER_BLENDMODE || mixertype == FSOUND_MIXER_QUALITY_FPU)
01117     {
01118                 wordsize = 4;
01119     }
01120 #endif
01121 
01122     double bandwidth = 50;
01123     double inputSamplingRate = 44100;
01124         double a0,b1,b2;
01125  
01126         // calculate resonant filter coeffs
01127     b2 = exp(-(F_TWO_PI) * (bandwidth / inputSamplingRate));
01128 
01129         while (length--)
01130         {
01131                 gCurrentFreq = (float)((0.999 * gCurrentFreq) + (0.001 * gTargetFreq));
01132                 gCurrentGain = (float)((0.999 * gCurrentGain) + (0.001 * gTargetGain));
01133                 gCurrentPanGainR = (float)((0.999 * gCurrentPanGainR) + (0.001 * gTargetPanGainR));
01134                 b1 = (-4.0 * b2) / (1.0 + b2) * cos(F_TWO_PI * (gCurrentFreq / inputSamplingRate));
01135             a0 = (1.0 - b2) * sqrt(1.0 - (b1 * b1) / (4.0 * b2));
01136                 double nextSample;
01137 
01138             // start with white noise
01139                 nextSample = ll_frand(2.0f) - 1.0f;
01140                                                                          
01141 #if 1 // LLAE_WIND_PINK apply pinking filter
01142                 gbuf0 = 0.997f * gbuf0 + 0.0126502f * nextSample; 
01143         gbuf1 = 0.985f * gbuf1 + 0.0139083f * nextSample;
01144         gbuf2 = 0.950f * gbuf2 + 0.0205439f * nextSample;
01145         gbuf3 = 0.850f * gbuf3 + 0.0387225f * nextSample;
01146         gbuf4 = 0.620f * gbuf4 + 0.0465932f * nextSample;
01147         gbuf5 = 0.250f * gbuf5 + 0.1093477f * nextSample;
01148                           
01149         nextSample = gbuf0 + gbuf1 + gbuf2 + gbuf3 + gbuf4 + gbuf5;
01150 #endif
01151                         
01152 #if 1 //LLAE_WIND_RESONANT // do a resonant filter on the noise
01153         nextSample = (double)( a0 * nextSample - b1 * gY0 - b2 * gY1 );
01154 
01155         gY1 = gY0;
01156         gY0 = nextSample;
01157 #endif
01158 
01159             nextSample *= gCurrentGain;
01160                 
01161                 MIXBUFFERFORMAT sample;
01162 
01163                 sample = llfloor(((F32)nextSample*32768.f*(1.0f - gCurrentPanGainR))+0.5f);
01164                 *(MIXBUFFERFORMAT*)cursamplep = clipSample((*(MIXBUFFERFORMAT*)cursamplep) + sample, -32768, 32767);
01165                 cursamplep += wordsize;
01166 
01167                 sample = llfloor(((F32)nextSample*32768.f*gCurrentPanGainR)+0.5f);
01168                 *(MIXBUFFERFORMAT*)cursamplep = clipSample((*(MIXBUFFERFORMAT*)cursamplep) + sample, -32768, 32767);
01169                 cursamplep += wordsize;
01170         }
01171 
01172         return newbuffer;
01173 }
01174 
01175 #endif  // LL_FMOD
01176 

Generated on Fri May 16 08:31:55 2008 for SecondLife by  doxygen 1.5.5