diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/app_settings/settings.xml | 66 | ||||
-rw-r--r-- | indra/newview/llviewercontrol.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llvoavatar.cpp | 218 | ||||
-rw-r--r-- | indra/newview/llvoavatar.h | 11 | ||||
-rw-r--r-- | indra/newview/llvoiceclient.cpp | 19 | ||||
-rw-r--r-- | indra/newview/llvoiceclient.h | 4 | ||||
-rw-r--r-- | indra/newview/llvoicevisualizer.cpp | 175 | ||||
-rw-r--r-- | indra/newview/llvoicevisualizer.h | 23 |
8 files changed, 430 insertions, 88 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1c421b343a..f6bedc3339 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3918,6 +3918,72 @@ <key>Value</key> <integer>1</integer> </map> + <key>LipSyncAah</key> + <map> + <key>Comment</key> + <string>Aah (jaw opening) babble loop</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>257998776531013446642343</string> + </map> + <key>LipSyncAahPowerTransfer</key> + <map> + <key>Comment</key> + <string>Transfer curve for Voice Interface power to aah lip sync amplitude</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>0000123456789</string> + </map> + <key>LipSyncEnabled</key> + <map> + <key>Comment</key> + <string>0 disable lip-sync, 1 enable babble loop</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>LipSyncOoh</key> + <map> + <key>Comment</key> + <string>Ooh (mouth width) babble loop</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>1247898743223344444443200000</string> + </map> + <key>LipSyncOohAahRate</key> + <map> + <key>Comment</key> + <string>Rate to babble Ooh and Aah (/sec)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>24.0</real> + </map> + <key>LipSyncOohPowerTransfer</key> + <map> + <key>Comment</key> + <string>Transfer curve for Voice Interface power to ooh lip sync amplitude</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>0012345566778899</string> + </map> <key>LocalCacheVersion</key> <map> <key>Comment</key> diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 69e611fd99..b834eb7e2e 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -426,6 +426,7 @@ bool handleVoiceClientPrefsChanged(const LLSD& newvalue) gVoiceClient->setCaptureDevice(inputDevice); std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); gVoiceClient->setRenderDevice(outputDevice); + gVoiceClient->setLipSyncEnabled(gSavedSettings.getU32("LipSyncEnabled")); } return true; } @@ -555,5 +556,6 @@ void settings_setup_listeners() gSavedSettings.getControl("VivoxDebugServerName")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("VoiceInputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("VoiceOutputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f3384c4a7e..0783468bb7 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -95,7 +95,6 @@ #include "llstatusbar.h" #include "lltargetingmotion.h" #include "lltexlayer.h" -#include "lltoolbar.h" #include "lltoolgrab.h" // for needsRenderBeam #include "lltoolmgr.h" // for needsRenderBeam #include "lltoolmorph.h" @@ -117,20 +116,13 @@ #include "llspatialpartition.h" #include "llglslshader.h" #include "llappviewer.h" -#include "lscript_byteformat.h" +#include "llsky.h" //#include "vtune/vtuneapi.h" -//Ventrella -#include "llgesturemgr.h" //needed to trigger the voice gestculations +#include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoicevisualizer.h" #include "llvoiceclient.h" -//end Ventrella - -// Direct imports, evil -extern LLSky gSky; -extern void set_avatar_character(void* charNameArg); -extern BOOL gRenderForSelect; LLXmlTree LLVOAvatar::sXMLTree; LLXmlTree LLVOAvatar::sSkeletonXMLTree; @@ -766,6 +758,10 @@ LLVOAvatar::LLVOAvatar( mStepOnLand = TRUE; mStepMaterial = 0; + mLipSyncActive = false; + mOohMorph = NULL; + mAahMorph = NULL; + //------------------------------------------------------------------------- // initialize joint, mesh and shape members //------------------------------------------------------------------------- @@ -950,10 +946,8 @@ LLVOAvatar::LLVOAvatar( //VTPause(); // VTune - //Ventrella mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) ); mCurrentGesticulationLevel = 0; - //END Ventrella } //------------------------------------------------------------------------ @@ -1887,6 +1881,26 @@ void LLVOAvatar::buildCharacter() updateHeadOffset(); //------------------------------------------------------------------------- + // initialize lip sync morph pointers + //------------------------------------------------------------------------- + mOohMorph = getVisualParam( "Lipsync_Ooh" ); + mAahMorph = getVisualParam( "Lipsync_Aah" ); + + // If we don't have the Ooh morph, use the Kiss morph + if (!mOohMorph) + { + llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl; + mOohMorph = getVisualParam( "Express_Kiss" ); + } + + // If we don't have the Aah morph, use the Open Mouth morph + if (!mAahMorph) + { + llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl; + mAahMorph = getVisualParam( "Express_Open_Mouth" ); + } + + //------------------------------------------------------------------------- // start default motions //------------------------------------------------------------------------- startMotion( ANIM_AGENT_HEAD_ROT ); @@ -2449,88 +2463,93 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // animate the character // store off last frame's root position to be consistent with camera position LLVector3 root_pos_last = mRoot.getWorldPosition(); - BOOL detailed_update = updateCharacter(agent); + bool voiceEnabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel(); - { - //Ventrella - bool voiceEnabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel(); - // disable voice visualizer when in mouselook - mVoiceVisualizer->setVoiceEnabled( voiceEnabled && !(mIsSelf && gAgent.cameraMouselook()) ); - if ( voiceEnabled ) - { - //---------------------------------------------------------------- - // Only do gesture triggering for your own avatar, and only when you're in a proximal channel. - //---------------------------------------------------------------- - if( mIsSelf ) + // disable voice visualizer when in mouselook + mVoiceVisualizer->setVoiceEnabled( voiceEnabled && !(mIsSelf && gAgent.cameraMouselook()) ); + if ( voiceEnabled ) + { + //---------------------------------------------------------------- + // Only do gesture triggering for your own avatar, and only when you're in a proximal channel. + //---------------------------------------------------------------- + if( mIsSelf ) + { + //---------------------------------------------------------------------------------------- + // The following takes the voice signal and uses that to trigger gesticulations. + //---------------------------------------------------------------------------------------- + int lastGesticulationLevel = mCurrentGesticulationLevel; + mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel(); + + //--------------------------------------------------------------------------------------------------- + // If "current gesticulation level" changes, we catch this, and trigger the new gesture + //--------------------------------------------------------------------------------------------------- + if ( lastGesticulationLevel != mCurrentGesticulationLevel ) { - //---------------------------------------------------------------------------------------- - // The following takes the voice signal and uses that to trigger gesticulations. - //---------------------------------------------------------------------------------------- - int lastGesticulationLevel = mCurrentGesticulationLevel; - mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel(); - - //--------------------------------------------------------------------------------------------------- - // If "current gesticulation level" changes, we catch this, and trigger the new gesture - //--------------------------------------------------------------------------------------------------- - if ( lastGesticulationLevel != mCurrentGesticulationLevel ) + if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF ) { - if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF ) - { - LLString gestureString = "unInitialized"; - if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; } - else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; } - else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; } - else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } - - // this is the call that Karl S. created for triggering gestures from within the code. - gGestureManager.triggerAndReviseString( gestureString ); - } - } - - } //if( mIsSelf ) - - //----------------------------------------------------------------------------------------------------------------- - // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer. - // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol. - // - // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been - // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. - //----------------------------------------------------------------------------------------------------------------- - if ( gVoiceClient->getIsSpeaking( mID ) ) - { - if ( ! mVoiceVisualizer->getCurrentlySpeaking() ) - { - mVoiceVisualizer->setStartSpeaking(); + LLString gestureString = "unInitialized"; + if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; } + else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; } + else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; } + else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } - //printf( "gAwayTimer.reset();\n" ); - } - - mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) ); - - if( mIsSelf ) - { - gAgent.clearAFK(); + // this is the call that Karl S. created for triggering gestures from within the code. + gGestureManager.triggerAndReviseString( gestureString ); } } - else + + } //if( mIsSelf ) + + //----------------------------------------------------------------------------------------------------------------- + // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer. + // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol. + // + // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been + // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. + //----------------------------------------------------------------------------------------------------------------- + if ( gVoiceClient->getIsSpeaking( mID ) ) + { + if ( ! mVoiceVisualizer->getCurrentlySpeaking() ) { - if ( mVoiceVisualizer->getCurrentlySpeaking() ) + mVoiceVisualizer->setStartSpeaking(); + + //printf( "gAwayTimer.reset();\n" ); + } + + mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) ); + + if( mIsSelf ) + { + gAgent.clearAFK(); + } + } + else + { + if ( mVoiceVisualizer->getCurrentlySpeaking() ) + { + mVoiceVisualizer->setStopSpeaking(); + + if ( mLipSyncActive ) { - mVoiceVisualizer->setStopSpeaking(); + if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); + if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); + + mLipSyncActive = false; + LLCharacter::updateVisualParams(); + dirtyMesh(); } } - - //-------------------------------------------------------------------------------------------- - // here we get the approximate head position and set as sound source for the voice symbol - // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) - //-------------------------------------------------------------------------------------------- - LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); - mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); - - }//if ( voiceEnabled ) - } - //End Ventrella + } + + //-------------------------------------------------------------------------------------------- + // here we get the approximate head position and set as sound source for the voice symbol + // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) + //-------------------------------------------------------------------------------------------- + LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); + mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset ); + + }//if ( voiceEnabled ) if (LLVOAvatar::sJointDebug) { @@ -2704,6 +2723,35 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) dirtyMesh(); } + // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync + if ( voiceEnabled && (gVoiceClient->lipSyncEnabled() > 0) && gVoiceClient->getIsSpeaking( mID ) ) + { + F32 ooh_morph_amount = 0.0f; + F32 aah_morph_amount = 0.0f; + + mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount ); + + if( mOohMorph ) + { + F32 ooh_weight = mOohMorph->getMinWeight() + + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); + + mOohMorph->setWeight( ooh_weight, FALSE ); + } + + if( mAahMorph ) + { + F32 aah_weight = mAahMorph->getMinWeight() + + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); + + mAahMorph->setWeight( aah_weight, FALSE ); + } + + mLipSyncActive = true; + LLCharacter::updateVisualParams(); + dirtyMesh(); + } + // update wind effect if ((LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)) { @@ -3883,7 +3931,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) { //LOD changed or new mesh created, allocate new vertex buffer if needed updateMeshData(); - mDirtyMesh = FALSE; + mDirtyMesh = FALSE; mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } @@ -9507,7 +9555,7 @@ BOOL LLVOAvatar::updateLOD() if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) { //LOD changed or new mesh created, allocate new vertex buffer if needed updateMeshData(); - mDirtyMesh = FALSE; + mDirtyMesh = FALSE; mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index b4a35d8e7e..8b742f153c 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -832,6 +832,17 @@ public: BOOL mAppearanceAnimating; //-------------------------------------------------------------------- + // we're morphing for lip sync + //-------------------------------------------------------------------- + bool mLipSyncActive; + + //-------------------------------------------------------------------- + // cached pointers morphs for lip sync + //-------------------------------------------------------------------- + LLVisualParam *mOohMorph; + LLVisualParam *mAahMorph; + + //-------------------------------------------------------------------- // static members //-------------------------------------------------------------------- static S32 sMaxVisible; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 10dea0e715..bba9fe1ccf 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -833,6 +833,7 @@ LLVoiceClient::LLVoiceClient() setCaptureDevice(captureDevice); std::string renderDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); setRenderDevice(renderDevice); + mLipSyncEnabled = gSavedSettings.getU32("LipSyncEnabled"); mTuningMode = false; mTuningEnergy = 0.0f; @@ -3607,6 +3608,24 @@ bool LLVoiceClient::voiceEnabled() return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice"); } +void LLVoiceClient::setLipSyncEnabled(U32 enabled) +{ + mLipSyncEnabled = enabled; +} + +U32 LLVoiceClient::lipSyncEnabled() +{ + + if ( mVoiceEnabled && stateDisabled != getState() ) + { + return mLipSyncEnabled; + } + else + { + return 0; + } +} + void LLVoiceClient::setUsePTT(bool usePTT) { if(usePTT && !mUsePTT) diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 5179bc099c..3ac5f0cdbf 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -210,6 +210,8 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient> void setMicGain(F32 volume); void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal) void setVivoxDebugServerName(std::string &serverName); + void setLipSyncEnabled(U32 enabled); + U32 lipSyncEnabled(); // PTT key triggering void keyDown(KEY key, MASK mask); @@ -516,6 +518,8 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient> LLTimer mUpdateTimer; + U32 mLipSyncEnabled; + typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t; observer_set_t mObservers; diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp index a7e1915171..38d435ff74 100644 --- a/indra/newview/llvoicevisualizer.cpp +++ b/indra/newview/llvoicevisualizer.cpp @@ -79,6 +79,35 @@ const F32 DEFAULT_MAXIMUM_GESTICULATION_AMPLITUDE = 1.0f; const F32 ONE_HALF = 1.0f; // to clarify intent and reduce magic numbers in the code. const LLVector3 WORLD_UPWARD_DIRECTION = LLVector3( 0.0f, 0.0f, 1.0f ); // Z is up in SL + +//------------------------------------------------------------------ +// handles parameter updates +//------------------------------------------------------------------ +static bool handleVoiceVisualizerPrefsChanged(const LLSD& newvalue) +{ + // Note: Ignore the specific event value, we look up the ones we want + LLVoiceVisualizer::setPreferences(); + return true; +} + +//------------------------------------------------------------------ +// Initialize the statics +//------------------------------------------------------------------ +bool LLVoiceVisualizer::sPrefsInitialized = false; +U32 LLVoiceVisualizer::sLipSyncEnabled = 0; +F32* LLVoiceVisualizer::sOoh = NULL; +F32* LLVoiceVisualizer::sAah = NULL; +U32 LLVoiceVisualizer::sOohs = 0; +U32 LLVoiceVisualizer::sAahs = 0; +F32 LLVoiceVisualizer::sOohAahRate = 0.0f; +F32* LLVoiceVisualizer::sOohPowerTransfer = NULL; +U32 LLVoiceVisualizer::sOohPowerTransfers = 0; +F32 LLVoiceVisualizer::sOohPowerTransfersf = 0.0f; +F32* LLVoiceVisualizer::sAahPowerTransfer = NULL; +U32 LLVoiceVisualizer::sAahPowerTransfers = 0; +F32 LLVoiceVisualizer::sAahPowerTransfersf = 0.0f; + + //----------------------------------------------- // constructor //----------------------------------------------- @@ -87,6 +116,7 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type ) { mCurrentTime = mTimer.getTotalSeconds(); mPreviousTime = mCurrentTime; + mStartTime = mCurrentTime; mVoiceSourceWorldPosition = LLVector3( 0.0f, 0.0f, 0.0f ); mSpeakingAmplitude = 0.0f; mCurrentlySpeaking = false; @@ -105,7 +135,7 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type ) "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", + "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", "29de489d-0491-fb00-7dab-f9e686d31e83.j2c" }; @@ -117,7 +147,23 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type ) mSoundSymbol.mWaveOpacity [i] = 1.0f; mSoundSymbol.mWaveExpansion [i] = 1.0f; } - + + // The first instance loads the initial state from prefs. + if (!sPrefsInitialized) + { + setPreferences(); + + // Set up our listener to get updates on all prefs values we care about. + gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncOohAahRate")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncOoh")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncAah")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncOohPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncAahPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + + sPrefsInitialized = true; + } + }//--------------------------------------------------- //--------------------------------------------------- @@ -144,6 +190,7 @@ void LLVoiceVisualizer::setVoiceEnabled( bool v ) //--------------------------------------------------- void LLVoiceVisualizer::setStartSpeaking() { + mStartTime = mTimer.getTotalSeconds(); mCurrentlySpeaking = true; mSoundSymbol.mActive = true; @@ -176,6 +223,130 @@ void LLVoiceVisualizer::setSpeakingAmplitude( F32 a ) //--------------------------------------------------- +void LLVoiceVisualizer::setPreferences( ) +{ + sLipSyncEnabled = gSavedSettings.getU32("LipSyncEnabled"); + sOohAahRate = gSavedSettings.getF32("LipSyncOohAahRate"); + + std::string oohString = gSavedSettings.getString("LipSyncOoh"); + lipStringToF32s (oohString, sOoh, sOohs); + + std::string aahString = gSavedSettings.getString("LipSyncAah"); + lipStringToF32s (aahString, sAah, sAahs); + + std::string oohPowerString = gSavedSettings.getString("LipSyncOohPowerTransfer"); + lipStringToF32s (oohPowerString, sOohPowerTransfer, sOohPowerTransfers); + sOohPowerTransfersf = (F32) sOohPowerTransfers; + + std::string aahPowerString = gSavedSettings.getString("LipSyncAahPowerTransfer"); + lipStringToF32s (aahPowerString, sAahPowerTransfer, sAahPowerTransfers); + sAahPowerTransfersf = (F32) sAahPowerTransfers; + +}//--------------------------------------------------- + + +//--------------------------------------------------- +// convert a string of digits to an array of floats. +// the result for each digit is the value of the +// digit multiplied by 0.11 +//--------------------------------------------------- +void LLVoiceVisualizer::lipStringToF32s ( std::string& in_string, F32*& out_F32s, U32& count_F32s ) +{ + delete[] out_F32s; // get rid of the current array + + count_F32s = in_string.length(); + if (count_F32s == 0) + { + // we don't like zero length arrays + + count_F32s = 1; + out_F32s = new F32[1]; + out_F32s[0] = 0.0f; + } + else + { + out_F32s = new F32[count_F32s]; + + for (U32 i=0; i<count_F32s; i++) + { + // we convert the characters 0 to 9 to their numeric value + // anything else we take the low order four bits with a ceiling of 9 + + U8 digit = in_string[i]; + U8 four_bits = digit % 16; + if (four_bits > 9) + { + four_bits = 9; + } + out_F32s[i] = 0.11f * (F32) four_bits; + } + } + +}//--------------------------------------------------- + + +//-------------------------------------------------------------------------- +// find the amount to blend the ooh and aah mouth morphs +//-------------------------------------------------------------------------- +void LLVoiceVisualizer::lipSyncOohAah( F32& ooh, F32& aah ) +{ + if( ( sLipSyncEnabled == 1 ) && mCurrentlySpeaking ) + { + U32 transfer_index = (U32) (sOohPowerTransfersf * mSpeakingAmplitude); + if (transfer_index < 0) + { + transfer_index = 0; + } + if (transfer_index >= sOohPowerTransfers) + { + transfer_index = sOohPowerTransfers - 1; + } + F32 transfer_ooh = sOohPowerTransfer[transfer_index]; + + transfer_index = (U32) (sAahPowerTransfersf * mSpeakingAmplitude); + if (transfer_index < 0) + { + transfer_index = 0; + } + if (transfer_index >= sAahPowerTransfers) + { + transfer_index = sAahPowerTransfers - 1; + } + F32 transfer_aah = sAahPowerTransfer[transfer_index]; + + F64 current_time = mTimer.getTotalSeconds(); + F64 elapsed_time = current_time - mStartTime; + U32 elapsed_frames = (U32) (elapsed_time * sOohAahRate); + U32 elapsed_oohs = elapsed_frames % sOohs; + U32 elapsed_aahs = elapsed_frames % sAahs; + + ooh = transfer_ooh * sOoh[elapsed_oohs]; + aah = transfer_aah * sAah[elapsed_aahs]; + + /* + llinfos << " elapsed frames " << elapsed_frames + << " ooh " << ooh + << " aah " << aah + << " transfer ooh" << transfer_ooh + << " transfer aah" << transfer_aah + << " start time " << mStartTime + << " current time " << current_time + << " elapsed time " << elapsed_time + << " elapsed oohs " << elapsed_oohs + << " elapsed aahs " << elapsed_aahs + << llendl; + */ + } + else + { + ooh = 0.0f; + aah = 0.0f; + } + +}//--------------------------------------------------- + + +//--------------------------------------------------- // this method is inherited from HUD Effect //--------------------------------------------------- void LLVoiceVisualizer::render() diff --git a/indra/newview/llvoicevisualizer.h b/indra/newview/llvoicevisualizer.h index 3543f254db..bb2ce55d4a 100644 --- a/indra/newview/llvoicevisualizer.h +++ b/indra/newview/llvoicevisualizer.h @@ -90,7 +90,9 @@ class LLVoiceVisualizer : public LLHUDEffect void setStopSpeaking(); // tell me when the av stops speaking bool getCurrentlySpeaking(); // the get for the above set VoiceGesticulationLevel getCurrentGesticulationLevel(); // based on voice amplitude, I'll give you the current "energy level" of avatar speech - + static void setPreferences( ); + static void lipStringToF32s ( std::string& in_string, F32*& out_F32s, U32& count_F32s ); // convert a string of digits to an array of floats + void lipSyncOohAah( F32& ooh, F32& aah ); void render(); // inherited from HUD Effect void packData(LLMessageSystem *mesgsys); // inherited from HUD Effect void unpackData(LLMessageSystem *mesgsys, S32 blocknum); // inherited from HUD Effect @@ -124,6 +126,7 @@ class LLVoiceVisualizer : public LLHUDEffect }; LLFrameTimer mTimer; // so I can ask the current time in seconds + F64 mStartTime; // time in seconds when speaking started F64 mCurrentTime; // current time in seconds, captured every step F64 mPreviousTime; // copy of "current time" from last frame SoundSymbol mSoundSymbol; // the sound symbol that appears over the avatar's head @@ -134,6 +137,24 @@ class LLVoiceVisualizer : public LLHUDEffect F32 mMaxGesticulationAmplitude; // this is the upper-limit of the envelope of detectable gesticulation leves F32 mMinGesticulationAmplitude; // this is the lower-limit of the envelope of detectable gesticulation leves + //--------------------------------------------------- + // private static members + //--------------------------------------------------- + + static U32 sLipSyncEnabled; // 0 disabled, 1 babble loop + static bool sPrefsInitialized; // the first instance will initialize the static members + static F32* sOoh; // the babble loop of amplitudes for the ooh morph + static F32* sAah; // the babble loop of amplitudes for the ooh morph + static U32 sOohs; // the number of entries in the ooh loop + static U32 sAahs; // the number of entries in the aah loop + static F32 sOohAahRate; // frames per second for the babble loop + static F32* sOohPowerTransfer; // the power transfer characteristics for the ooh amplitude + static U32 sOohPowerTransfers; // the number of entries in the ooh transfer characteristics + static F32 sOohPowerTransfersf; // the number of entries in the ooh transfer characteristics as a float + static F32* sAahPowerTransfer; // the power transfer characteristics for the aah amplitude + static U32 sAahPowerTransfers; // the number of entries in the aah transfer characteristics + static F32 sAahPowerTransfersf; // the number of entries in the aah transfer characteristics as a float + };//----------------------------------------------------------------- // end of LLVoiceVisualizer class //------------------------------------------------------------------ |