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