summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/app_settings/settings.xml66
-rw-r--r--indra/newview/llviewercontrol.cpp2
-rw-r--r--indra/newview/llvoavatar.cpp218
-rw-r--r--indra/newview/llvoavatar.h11
-rw-r--r--indra/newview/llvoiceclient.cpp19
-rw-r--r--indra/newview/llvoiceclient.h4
-rw-r--r--indra/newview/llvoicevisualizer.cpp175
-rw-r--r--indra/newview/llvoicevisualizer.h23
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
//------------------------------------------------------------------