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 
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 
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);       
00085                         min_len = llmin( dst_size - 1, source_len );
00086                         memcpy(dest, src, min_len);       
00087                 }
00088                 dest[min_len] = '\0';
00089         }
00090         return source_len;
00091 }
00092 #else
00093 
00094 
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         
00118         if (!FSOUND_SetMinHardwareChannels(num_channels + 1))
00119         {
00120                 llwarns<< "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00121         }
00122 
00123         llinfos << "LLAudioEngine_FMOD::init() initializing FMOD" << llendl;
00124 
00125         F32 version = FSOUND_GetVersion();
00126         if (version < FMOD_VERSION)
00127         {
00128                 llwarns << "Error : You are using the wrong FMOD version (" << version
00129                         << ")!  You should be using FMOD " << FMOD_VERSION << llendl;
00130                 
00131         }
00132 
00133         U32 fmod_flags = 0x0;
00134 
00135 #if LL_WINDOWS
00136         
00137         
00138         
00139         
00140         
00141         if (!FSOUND_SetHWND(userdata))
00142         {
00143                 llwarns << "Error setting FMOD window: "
00144                         << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00145                 return FALSE;
00146         }
00147         
00148         
00149         
00150         
00151         fmod_flags |= FSOUND_INIT_GLOBALFOCUS;
00152 #endif
00153 
00154 #if LL_LINUX
00155         
00156 
00157         
00158         
00159         
00160         if (getenv("LL_VALGRIND"))              
00161         {
00162                 llinfos << "Pacifying valgrind in FMOD init." << llendl;
00163                 FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU);
00164         }
00165 
00166         
00167         
00168         
00169         
00170         
00171         
00172         
00173         BOOL audio_ok = FALSE;
00174 
00175         if (!audio_ok)
00176                 if (NULL == getenv("LL_BAD_ESD")) 
00177                 {
00178                         llinfos << "Trying ESD audio output..." << llendl;
00179                         if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) &&
00180                            FSOUND_Init(44100, num_channels, fmod_flags))
00181                         {
00182                                 llinfos << "ESD audio output initialized OKAY"
00183                                         << llendl;
00184                                 audio_ok = TRUE;
00185                         } else {
00186                                 llwarns << "ESD audio output FAILED to initialize: "
00187                                         << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00188                         }
00189                 } else {
00190                         llinfos << "ESD audio output SKIPPED" << llendl;
00191                 }
00192 
00193         if (!audio_ok)
00194                 if (NULL == getenv("LL_BAD_OSS"))        
00195                 {
00196                         llinfos << "Trying OSS audio output..." << llendl;
00197                         if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) &&
00198                            FSOUND_Init(44100, num_channels, fmod_flags))
00199                         {
00200                                 llinfos << "OSS audio output initialized OKAY" << llendl;
00201                                 audio_ok = TRUE;
00202                         } else {
00203                                 llwarns << "OSS audio output FAILED to initialize: "
00204                                         << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00205                         }
00206                 } else {
00207                         llinfos << "OSS audio output SKIPPED" << llendl;
00208                 }
00209 
00210         if (!audio_ok)
00211                 if (NULL == getenv("LL_BAD_ALSA"))              
00212                 {
00213                         llinfos << "Trying ALSA audio output..." << llendl;
00214                         if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) &&
00215                            FSOUND_Init(44100, num_channels, fmod_flags))
00216                         {
00217                                 llinfos << "ALSA audio output initialized OKAY" << llendl;
00218                                 audio_ok = TRUE;
00219                         } else {
00220                                 llwarns << "ALSA audio output FAILED to initialize: "
00221                                         << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00222                         }
00223                 } else {
00224                         llinfos << "OSS audio output SKIPPED" << llendl;
00225                 }
00226 
00227         if (!audio_ok)
00228         {
00229                 llwarns << "Overall audio init failure." << llendl;
00230                 return FALSE;
00231         }
00232 
00233         
00234         
00235         
00236         
00237 
00238         
00239         
00240         switch (FSOUND_GetOutput())
00241         {
00242         case FSOUND_OUTPUT_NOSOUND: llinfos << "Audio output: NoSound" << llendl; break;
00243         case FSOUND_OUTPUT_OSS: llinfos << "Audio output: OSS" << llendl; break;
00244         case FSOUND_OUTPUT_ESD: llinfos << "Audio output: ESD" << llendl; break;
00245         case FSOUND_OUTPUT_ALSA: llinfos << "Audio output: ALSA" << llendl; break;
00246         default: llinfos << "Audio output: Unknown!" << llendl; break;
00247         };
00248 
00249 #else // LL_LINUX
00250 
00251         
00252         if (!FSOUND_Init(44100, num_channels, fmod_flags))
00253         {
00254                 llwarns << "Error initializing FMOD: "
00255                         << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00256                 return FALSE;
00257         }
00258         
00259 #endif
00260 
00261         initInternetStream();
00262 
00263         llinfos << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << llendl;
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                 
00363                 
00364                 
00365 
00366                 wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
00367 
00368                 
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 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 
00420 
00421 
00422 
00423 
00424 
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 
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                 
00468                 
00469 
00470                 LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer();
00471 
00472                 
00473                 FSOUND_SAMPLE *samplep = bufferp->getSample();
00474                 if (!samplep)
00475                 {
00476                         
00477                         
00478                         llerrs << "No FMOD sample!" << llendl;
00479                         return FALSE;
00480                 }
00481 
00482 
00483                 
00484                 
00485                 mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), TRUE);
00486 
00487                 
00488         }
00489 
00490         
00491         if (mCurrentSourcep)
00492         {
00493                 
00494                 if (!FSOUND_SetVolume(mChannelID, llround(mCurrentSourcep->getGain() * 255.0f)))
00495                 {
00496 
00497                 }
00498                 
00499                 if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
00500                 {
00501 
00502 
00503 
00504                 }
00505         }
00506 
00507         return TRUE;
00508 }
00509 
00510 
00511 void LLAudioChannelFMOD::update3DPosition()
00512 {
00513         if (!mChannelID)
00514         {
00515                 
00516                 return;
00517         }
00518 
00519         LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp;
00520         if (!bufferp)
00521         {
00522                 
00523                 
00524                 return;
00525         }
00526 
00527         if (mCurrentSourcep->isAmbient())
00528         {
00529                 
00530                 bufferp->set3DMode(FALSE);
00531         }
00532         else
00533         {
00534                 
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                 
00552                 return;
00553         }
00554 
00555         
00556         
00557         
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                 
00573                 return;
00574         }
00575 
00576         
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                 
00609                 return;
00610         }
00611 
00612         U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength();
00613         
00614         if (!FSOUND_SetCurrentPosition(mChannelID, position))
00615         {
00616                 llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl;
00617         }
00618 
00619         
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 
00638 
00639 
00640 
00641 LLAudioBufferFMOD::LLAudioBufferFMOD()
00642 {
00643         mSamplep = NULL;
00644 }
00645 
00646 
00647 LLAudioBufferFMOD::~LLAudioBufferFMOD()
00648 {
00649         if (mSamplep)
00650         {
00651                 
00652                 FSOUND_Sample_Free(mSamplep);
00653                 mSamplep = NULL;
00654         }
00655 }
00656 
00657 
00658 BOOL LLAudioBufferFMOD::loadWAV(const char *filename)
00659 {
00660         
00661         
00662         if (filename == NULL)
00663         {
00664                 
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                 
00673                 return FALSE;
00674         }
00675         apr_file_close(apr_file);
00676 
00677         if (mSamplep)
00678         {
00679                 
00680                 FSOUND_Sample_Free(mSamplep);
00681                 mSamplep = NULL;
00682         }
00683 
00684         
00685 #if LL_WINDOWS
00686         
00687         
00688         
00689         FILE* sound_file = LLFile::fopen(filename,"rb");        
00690         if (sound_file)
00691         {
00692                 fseek(sound_file,0,SEEK_END);
00693                 U32     file_length = ftell(sound_file);        
00694                 size_t  read_count;
00695                 fseek(sound_file,0,SEEK_SET);   
00696                 char*   buffer = new char[file_length];
00697                 llassert(buffer);
00698                 read_count = fread((void*)buffer,file_length,1,sound_file);
00699                 if(ferror(sound_file)==0 && (read_count == 1)){
00700                         unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY;
00701                                                                         
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                 
00714                 llwarns << "Could not load data '" << filename << "': "
00715                                 << FMOD_ErrorString(FSOUND_GetError()) << llendl;
00716 
00717                 
00718                 
00719                 
00720                 
00721                 
00722                 LLFile::remove(filename);
00723                 return FALSE;
00724         }
00725 
00726         
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 
00766 
00767 void LLAudioEngine_FMOD::initInternetStream()
00768 {
00769         
00770         
00771     FSOUND_Stream_SetBufferSize(200);
00772 
00773         
00774         
00775         
00776         
00777 
00778         
00779         
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         
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 
00812 
00813 
00814 
00815 
00816 
00817 
00818 
00819 
00820 
00821 
00822 
00823 
00824 
00825 
00826 
00827 
00828     return TRUE;
00829 }
00830 
00831 
00832 void LLAudioEngine_FMOD::updateInternetStream()
00833 {
00834         
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         
00852         if (!mCurrentInternetStreamp)
00853         {
00854                 return;
00855         }
00856 
00857     int open_state = mCurrentInternetStreamp->getOpenState();
00858 
00859         if (!open_state)
00860         {
00861                 
00862 
00863 
00864                 
00865                 if (mInternetStreamChannel < 0)
00866                 {
00867                         mInternetStreamChannel = mCurrentInternetStreamp->startStream();
00868 
00869                         if (mInternetStreamChannel != -1)
00870                         {
00871                                 
00872                                 setInternetStreamGain(mInternetStreamGain);
00873                                 FSOUND_SetPaused(mInternetStreamChannel, FALSE);
00874                                 
00875                         }
00876                 }
00877         }
00878                 
00879         switch(open_state)
00880         {
00881         default:
00882         case 0:
00883                 
00884                 break;
00885         case -1:
00886                 
00887                 llwarns << "InternetStream - invalid handle" << llendl;
00888                 stopInternetStream();
00889                 return;
00890         case -2:
00891                 
00892                 
00893                 break;
00894         case -3:
00895                 
00896                 llwarns << "InternetSteam - failed to open" << llendl;
00897                 stopInternetStream();
00898                 return;
00899         case -4:
00900                 
00901                 
00902                 break;
00903         case -5:
00904                 
00905                 
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                 
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 
00959 
00960 int LLAudioEngine_FMOD::isInternetStreamPlaying()
00961 {
00962         if (mCurrentInternetStreamp)
00963         {
00964                 return 1; 
00965         }
00966         else if (mInternetStreamURL[0])
00967         {
00968                 return 2; 
00969         }
00970         else
00971         {
00972                 return 0;
00973         }
00974 }
00975 
00976 
00977 void LLAudioEngine_FMOD::getInternetStreamInfo(char* artist_out, char* title_out)
00978 {
00979         
00980         
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         
01024         if (!mInternetStream || getOpenState())
01025         {
01026                 llwarns << "No internet stream to start playing!" << llendl;
01027                 return -1;
01028         }
01029 
01030         
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 
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 
01103 
01104 
01105 
01106 
01107 
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         
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             
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