Main Page   Class Hierarchy   Compound List   File List   Compound Members  

VisageLinkDoc.cpp

00001 // VisageLinkDoc.cpp : implementation of the CVisageLinkDoc class
00002 //
00003 
00004 #include "stdafx.h"
00005 #include "VisageLink.h"
00006 
00007 #include "VisageLinkDoc.h"
00008 
00009 /*
00010 #ifdef _DEBUG
00011 #define new DEBUG_NEW
00012 #undef THIS_FILE
00013 static char THIS_FILE[] = __FILE__;
00014 #endif
00015 */
00016 
00017 #include "OpenGLWnd.h"
00018 #include "math.h"
00019 #include "MainFrm.h"
00020 #include "SimpleFacialExpression.h"
00021 #include "SimpleFbaAction.h"
00022 
00023 
00024 /////////////////////////////////////////////////////////////////////////////
00025 // CVisageLinkDoc
00026 
00027 IMPLEMENT_DYNCREATE(CVisageLinkDoc, CDocument)
00028 
00029 BEGIN_MESSAGE_MAP(CVisageLinkDoc, CDocument)
00030         //{{AFX_MSG_MAP(CVisageLinkDoc)
00031         ON_COMMAND(ID_FILE_START, OnFileStart)
00032         ON_COMMAND(ID_FILE_SPEAK, OnFileSpeak)
00033         ON_COMMAND(ID_OPTIONS_GAZEFOLLOWINGVOR, OnOptionsGazefollowingvor)
00034         ON_COMMAND(ID_OPTIONS_DISABLEGAZEFOLLOWINGVOR, OnOptionsDisablegazefollowingvor)
00035         //}}AFX_MSG_MAP
00036 END_MESSAGE_MAP()
00037 
00038 /////////////////////////////////////////////////////////////////////////////
00039 // CVisageLinkDoc construction/destruction
00040 
00041 CVisageLinkDoc::CVisageLinkDoc()
00042 {
00043         animationStarted = false;
00044         m_FAPlayer = new FAPlayer();
00045         vor = new SimpleVORAction();
00046 }
00047 
00048 CVisageLinkDoc::~CVisageLinkDoc()
00049 {
00050 }
00051 
00052 BOOL CVisageLinkDoc::OnNewDocument()
00053 {
00054         if (!CDocument::OnNewDocument())
00055                 return FALSE;
00056 
00057         // TODO: add reinitialization code here
00058         // (SDI documents will reuse this document)
00059 
00060         return TRUE;
00061 }
00062 
00063 BOOL CVisageLinkDoc::OnOpenDocument(LPCTSTR lpszPathName) 
00064 {
00065         return TRUE;
00066 }
00067 
00068 
00069 
00070 /////////////////////////////////////////////////////////////////////////////
00071 // CVisageLinkDoc serialization
00072 
00073 void CVisageLinkDoc::Serialize(CArchive& ar)
00074 {
00075         if (ar.IsStoring())
00076         {
00077                 // TODO: add storing code here
00078         }
00079         else
00080         {
00081                 // TODO: add loading code here
00082         }
00083 }
00084 
00085 
00086 
00087 /**
00088 * A simple wave action.
00089 * This is an implementation of an extremely simple hand waving action, actually just a very basic movement of the
00090 * right arm.
00091 */
00092 class SimpleWaveAction : public SimpleFbaAction
00093 {
00094 public:
00095         FBAPs *getFBAPs(long globalTime, FBAPs *lastFBAPs, AFM *afm)
00096         {
00097                 long localTime = globalTime - globalStartTime;
00098                 float angle = 0.0f;
00099                 
00100                 
00101                 if(!fbaps)
00102                         fbaps = new FBAPs();
00103                 
00104                 
00105                 angle = -sin((1000+localTime)/300.0f) * 300000;
00106                 
00107                 fbaps->setBAP(r_shoulder_flexion,(int)angle);
00108                 
00109                 if(localTime < 500)
00110                         return(fbaps);
00111                 else
00112                         return NULL;
00113         };
00114 };
00115 
00116 
00117 /**
00118 * Processing of the TTS viseme notification events.
00119 * This function is the implementation of a virtual function from the Visagesapi5ttsObserver class.
00120 * It is not to be called directly. Rather, the instance of CVisageLinkDoc is attached to the
00121 * Visagesapi5tts, which calls the Notify() function as appropriate, and passes the appropriate
00122 * parameters to it.
00123 *
00124 * This gives the possibility of additional control over the animation parameters generated by TTS.
00125 * In this example we do not use it so it is empty.
00126 *
00127 * @param faps pointer to FAPs structure, or NULL at the end of speech.
00128 * @param cp pointer to the coding parameters used when encoding the animation into a file; 
00129 * @param pts current TTS speech bit stream time in milliseconds. 
00130 * @param vtts instance of Visagesapi5tts that called the function; this can be used for identification if more than one Visagesapi5tts object is used at the same time
00131 *
00132 * @see Visagesapi5ttsObserver
00133 * @see preRender()
00134 */
00135 void  CVisageLinkDoc::Notify (Visagesapi5tts *vtts, FBAPs *fbaps, CodingParameters *cp, long pts)
00136 {
00137 }
00138 
00139 /**
00140 * Processing of the TTS bookmark events.
00141 * This function is the implementation of a virtual function from the Visagesapi5ttsObserver class.
00142 * It is not to be called directly. Rather, the instance of CVisageLinkDoc is attached to the
00143 * Visagesapi5tts, which calls the BookMark() function as appropriate, and passes the appropriate
00144 * parameters to it.
00145 *
00146 * In this example we use the bookmarks to insert simple facial expressions or animations at particular times
00147 * during the speech. This is done by playing a SimpleFacialExpression. The expression is
00148 * initialized with the name from the bookmark tag, e.g. "surprise" or "joy". See SimpleFacialExpression
00149 * for the list of supported expression names.
00150 *
00151 * The other bookmark that can occur is "wave", and if it is found we insert a simple waving animation - just moving the right hand.
00152 *
00153 * @param qTimeStamp bookmark time stamp in milliseconds. This is bookmark's TTS speech bit stream time.
00154 * @param dwMarkNum bookmark code number (the number that was entered in the SAPI control tag as \\Mrk=number\.
00155 * @param vtts instance of Visagesapi5tts that called the function; this can be used for identification if more than one Visagesapi5tts object is used at the same time
00156 *
00157 * @see Visagesapi5ttsObserver
00158 * @see SimpleFacialExpression
00159 */
00160 void  CVisageLinkDoc::BookMark (Visagesapi5tts *vtts, long qTimeStamp, DWORD dwMarkNum, WCHAR *markText)
00161 {
00162         CString t(markText);
00163         if(!t.CompareNoCase("wave"))
00164         {
00165                 SimpleWaveAction *wave = new SimpleWaveAction();
00166                 m_FAPlayer->playTrack(wave);
00167         }
00168         else
00169         {
00170                 SimpleFacialExpression *exp = new SimpleFacialExpression((char*)markText,2200,1.3f);
00171                 m_FAPlayer->playTrack(exp);
00172         }
00173 }
00174 
00175 /**
00176 * Processing of the TTS start speech events.
00177 * This function is the implementation of a virtual function from the Visagesapi5ttsObserver class.
00178 * It is not to be called directly. Rather, the instance of CVisageLinkDoc is attached to the
00179 * Visagesapi5tts, which calls the StartSpeech() function as appropriate, and passes the appropriate
00180 * parameters to it.
00181 *
00182 * In this example we use the bookmarks to insert simple expressions and animations at particular times
00183 * during the speech. Some bookmarks are already inserted in the input text file. We use this function
00184 * as a simple filter to insert additional bookmarks. 
00185 * 
00186 * So, when the string "surpr" is encountered, a bookmark for the surprize expression is inserted. 
00187 *
00188 * This is a very simple example of using the Visagesapi5ttsObserver for processing the text and 
00189 * inserting appropriate actions.
00190 *
00191 * @param qTimeStamp bookmark time stamp in milliseconds. This is bookmark's TTS speech bit stream time.
00192 * @param dwMarkNum bookmark code number (the number that was entered in the SAPI control tag as \\Mrk=number\.
00193 * @param vtts instance of Visagesapi5tts that called the function; this can be used for identification if more than one Visagesapi5tts object is used at the same time
00194 *
00195 * @see Visagesapi5ttsObserver
00196 * @see SimpleFacialExpression
00197 */
00198 void CVisageLinkDoc::StartSpeech (Visagesapi5tts *vtts, WCHAR *text)
00199 {
00200         CString t(text);
00201         int ind = 0;
00202         while(ind != -1)
00203         {
00204                 ind = t.Find("surpr",ind);
00205                 if(ind != -1)
00206                 {
00207                         t.Insert(ind,"<BOOKMARK MARK='surprise'/>");
00208                         ind += 32;
00209                 }
00210         }
00211 
00212 
00213         ind = t.GetLength();
00214 
00215         char *text1 = t.GetBuffer(ind);
00216 
00217         Visagesapi5tts::toUnicode(text,text1);
00218 }
00219 
00220 /////////////////////////////////////////////////////////////////////////////
00221 // CVisageLinkDoc diagnostics
00222 
00223 #ifdef _DEBUG
00224 void CVisageLinkDoc::AssertValid() const
00225 {
00226         CDocument::AssertValid();
00227 }
00228 
00229 void CVisageLinkDoc::Dump(CDumpContext& dc) const
00230 {
00231         CDocument::Dump(dc);
00232 }
00233 #endif //_DEBUG
00234 
00235 /////////////////////////////////////////////////////////////////////////////
00236 // CVisageLinkDoc commands
00237 
00238 /**
00239 * Check if all necessary files are present.
00240 * 
00241 * All the file names in this example are hard-coded. This function checks if the files are actually
00242 * present and gives error messages if they are not. The example should be run in the VisageLink folder where all necessary files are present.
00243 */
00244 void CVisageLinkDoc::CheckFiles() 
00245 {
00246                 FILE * testFP;
00247 
00248                 if(!(testFP = fopen("p2v.cfg","r")))
00249                 {
00250                         CString msg;
00251                         msg = "The working folder does not contain the file p2v.cfg, necessary for the TTS. This file can be found in the visageSDK/lib folder, and also in the visageSDK/Samples/VisageLink folder. It is best to run this example in visageSDK/Samples/VisageLink folder.";
00252                         MessageBox(0,msg,"Error",MB_ICONERROR);
00253                         exit(1);
00254                 }
00255                 else fclose(testFP);
00256 
00257 
00258 
00259                 if(!(testFP = fopen("test-sapi5-expression.txt","r")))
00260                 {
00261                         CString msg;
00262                         msg = "The working folder does not contain the example file test-sapi5-expression.txt, necessary to run this example. This file can be found in the visageSDK/Samples/VisageLink folder. It is best to run this example in visageSDK/Samples/VisageLink folder.";
00263                         MessageBox(0,msg,"Error",MB_ICONERROR);
00264                         exit(1);
00265                 }
00266                 else fclose(testFP);
00267 
00268 
00269         if(!(testFP = fopen("dubravka.afm","r")))
00270         {
00271                 CString msg;
00272                 msg = "The working folder does not contain the file dubravka.afm, necessary to run this example. This file can be found in the visageSDK/Samples/VisageLink folder. It is best to run this example in visageSDK/Samples/VisageLink folder.";
00273                 MessageBox(0,msg,"Error",MB_ICONERROR);
00274                 exit(1);
00275         }
00276         else fclose(testFP);
00277         
00278         if(!(testFP = fopen("headmotion_short.fba","r")))
00279         {
00280                 CString msg;
00281                 msg = "The working folder does not contain the file headmotion_short.fba, necessary to run this example. This file can be found in the visageSDK/Samples/VisageLink folder. It is best to run this example in visageSDK/Samples/VisageLink folder.";
00282                 MessageBox(0,msg,"Error",MB_ICONERROR);
00283                 exit(1);
00284         }
00285         else fclose(testFP);
00286 }
00287 
00288 /**
00289 * Initialize everything and start the animation.
00290 * 
00291 * This method is called when the File->Start menu option is selected. It performs all necessary initializations, and starts the FAPlayer.
00292 *
00293 * Specifically:
00294 * - a check is performed to see if all required files are present
00295 * - a face/body model is loaded and attached to the FAPlayer
00296 * - a base animation track (simple head motion and eye blinks) is loaded from file into the player; it will loop forever. This makes the animation look nicer, and provides some basic action to the FAPlayer so that it continues playing (if the player is empty, the play() method would just return because there is nothing to play)
00297 * - the specch synthesis object vtts is initialised and added as an animation track to the player
00298 * - the rendering mechanism is started
00299 * - the FAPlayer play() method is called to start the player.
00300 */
00301 void CVisageLinkDoc::OnFileStart() 
00302 {
00303 
00304         
00305         if(animationStarted)  // If animation is already started do nothing. 
00306                 return;  
00307 
00308         animationStarted = true;
00309         
00310         CheckFiles();         // check if all necessary files are present       
00311         
00312         AFM *afm = new AFM("dubravka.afm");          // load the face/body model
00313         m_FAPlayer->init(afm);                    // add the model to the player, and add this CVisageLinkDoc as renderer
00314 //      m_FAPlayer->setSleepTimePerCycle(100);
00315 
00316         FbaFileAction *trk = m_FAPlayer->addTrack("headmotion_short.fba", 1, 0);    // start playing the base animation
00317         trk->smoothZeroValues(); // smooth the zero values to avoid jerks when merging with other actions
00318 
00319         vtts = new Visagesapi5tts("."); // construct a TTS
00320         vtts->setSpeaker("Mary"); // set a female voice
00321         m_FAPlayer->addTrack(vtts);// add vtts as an animation track to the FAPlayer
00322         vtts->attach(this);             // attach this CVisageLinkDoc to the vtts as observer; 
00323                                         // it will get viseme and bookmark events; 
00324                                         // bookmark events are used to insert expressions
00325         
00326         // get the renderer
00327         CMainFrame* pMainWnd = (CMainFrame*)AfxGetMainWnd();
00328         COpenGLWnd *pOpenGL = pMainWnd->GetOpenGLWnd();
00329 
00330         // initialise the renderer with the new face model
00331         pOpenGL->Init(m_FAPlayer->getFaceModel()); 
00332         
00333         m_FAPlayer->play();      // start the player. 
00334 }
00335 
00336 /**
00337 * Speak.
00338 * 
00339 *  This method is called when the File->Speak menu option is selected. It reads the speech from the file and pronounces it using the speech synthesis object vtts.
00340 */
00341 void CVisageLinkDoc::OnFileSpeak() 
00342 {
00343         if(!animationStarted)                        // if the animation is not initialized, we can not speak yet
00344                 return;
00345 
00346         FILE *fp;
00347         char s[2000];
00348         
00349         fp = fopen("test-sapi5-expression.txt","r"); // open the file with the speech to pronounce
00350         fgets(s,2000,fp);                                    // read the text from the file (only the first line is treated)
00351         fclose(fp);                                  // close the file
00352         
00353         
00354         vtts->speak(s,1);                                                        // speak
00355 }
00356 
00357 /**
00358 * Enable gaze following (vestibulo-ocular reflex).
00359 * 
00360 * This method is called when the File->Enable Gaze Following menu option is selected. 
00361 *
00362 * It enables the gaze following (vestibulo-ocular reflex) by attaching the vor object (a SimpleVORAction)
00363 * to the FAPlayer.
00364 *
00365 * @see SimpleVORAction
00366 */
00367 void CVisageLinkDoc::OnOptionsGazefollowingvor() 
00368 {
00369         if(!vor) return;
00370         if(!m_FAPlayer) return;
00371         
00372         m_FAPlayer->addTrack(vor);
00373 }
00374 
00375 /**
00376 * Disable gaze following (vestibulo-ocular reflex).
00377 * 
00378 * This method is called when the File->Disable Gaze Following menu option is selected. 
00379 *
00380 * It disables the gaze following (vestibulo-ocular reflex) by  removing the vor object (a SimpleVORAction)
00381 * from the FAPlayer.
00382 *
00383 * @see SimpleVORAction
00384 */
00385 void CVisageLinkDoc::OnOptionsDisablegazefollowingvor() 
00386 {
00387         if(!vor) return;
00388         if(!m_FAPlayer) return;
00389         
00390         m_FAPlayer->removeTrack(vor);
00391 }

Generated on Wed Nov 8 16:13:38 2006 for VisageLink by doxygen 1.3.1