copying everything to the clipboard. The hand-shaking file is
renamed to cause the speech to occur. Normally, the only
thing left to do is wait for the file to be renamed to indicate
the operation is complete. If the parameter t is nonzero
though, the function AnimateSpeech is called to produce the
You might assume that synchronizing the lip movement
generated by AnimateSpeech would require complicated
programming, but since the spoken phrases are computer
generated the time spent for all constants and vowels is
more consistent than human speech, making it possible to
create a very simple algorithm.
The basic principle of the algorithm is easy. For each
word spoken, the letters will be examined one by one. If
there are several constants or vowels in a row, the mouth
will only change for the first one. For a constant, the lips will
form the shape shown in Figure 5. When a vowel is found,
two possible actions are possible. If the vowel is an O, then
the mouth will change to the shape in Figure 6. Any other
vowel will cause the mouth to look like Figure 7. The only
exception to the above is that the vowel E at the end of a
word is ignored.
We experimented with many phrases to determine the
relative time that Windows takes to say constants and
vowels. The routines that we created to draw the mouths
shown in Figures 5, 6, and 7 will maintain the expression for
a period of time based on the second number passed to the
Say function. We found a value of 55 provides the delays
needed to synchronize with voices spoken at Windows’
SERVO 03.2014 49
main: call InitSensors(0,0,0,0) //gosub InitAnimateSay Expr = "Hello goodbye" // subst 55 for 0 below for graphics call Say(Expr,0) end sub Say(s,t) setcbtext("Say,"+s) // tell the Interface program what to say // now trigger utility to perform FileRename ("RBsTurn.txt","SensorsTurn.txt") // produce animation if requested if t then call AnimateSpeech(s,t) // continue waiting to ensure utility has // finished while !fileexists("RBsTurn.txt") wend return Figure 2. Figure 3.
sub AnimateSpeech(s,pause) answer=0 LineWidth 20 s=Lower(s)+" *" _SpeechDelay=pause mfromstring words,s," " for i=0 to _MaxWords-1 State="" if words[i]="*" then break // animate next word for j=1 to Length(words[i]) L=SubString(words[i],j,1) call IsVowel(L,answer) if (answer and (State="C")) or ((!answer) and (State="V")) or (State="") if answer if L="o" gosub Osound elseif !((L="e") and (Length(words [i])=j)) gosub Vsound // all other vowels endif State="V" else gosub Constant State="C" endif endif next next gosub Smile return Figure 4.