PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/v2-45/mh/lib/Voice_Text.pm

#
Perl | 308 lines | 171 code | 31 blank | 106 comment | 36 complexity | ea2036936515ced72ec954084b2a6041 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, GPL-3.0
  1. package Voice_Text;
  2. use strict;
  3. my ($VTxt, $VTxt_festival, $VV_TTS, $save_mute_esd, $save_change_volume, %pronouncable);
  4. my ($ViaVoiceTTS); #mod for ViaVoiceTTS
  5. sub init {
  6. if ($main::config_parms{voice_text} =~ /festival/i) {
  7. print "Creating festival TTS socket\n";
  8. my $festival_address = "$main::config_parms{festival_host}:$main::config_parms{festival_port}";
  9. $VTxt_festival = new Socket_Item(undef, undef, $festival_address);
  10. start $VTxt_festival;
  11. if ($main::config_parms{festival_init_cmds}) {
  12. print "Data sent to festival: $main::config_parms{festival_init_cmds}\n";
  13. set $VTxt_festival qq[$main::config_parms{festival_init_cmds}];
  14. }
  15. }
  16. if ($main::config_parms{voice_text} =~ /vv_tts/i) {
  17. my $pgm_root = $main::Pgm_Root;
  18. $VV_TTS = qq[$main::Pgm_Path/vv_tts.pl];
  19. $VV_TTS .= " -prescript " . $main::config_parms{vv_tts_prescript} if $main::config_parms{vv_tts_prescript};
  20. $VV_TTS .= " -postscript " . $main::config_parms{vv_tts_postscript} if $main::config_parms{vv_tts_postscript};
  21. $VV_TTS .= " -playcmd " . $main::config_parms{vv_tts_playcmd} if $main::config_parms{vv_tts_playcmd};
  22. $VV_TTS .= " -default_sound " . $main::config_parms{vv_tts_default_sound} if $main::config_parms{vv_tts_default_sound};
  23. print "VV TTS command string: $VV_TTS\n";
  24. }
  25. if ($main::config_parms{voice_text} =~ /viavoice/i) {
  26. $ViaVoiceTTS = 1; #define $ViaVoiceTTS if 'voice_text=viavoice'
  27. print "Using ViaVoiceTTS.pm for speech.\n";
  28. }
  29. if ($main::config_parms{voice_text} =~ /ms/i and $main::OS_win) {
  30. print "Creating MS TTS object\n";
  31. # $VTxt = CreateObject OLE 'Speech.VoiceText';
  32. $VTxt = Win32::OLE->new('Speech.VoiceText');
  33. unless ($VTxt) {
  34. print "\n\nError, could not create Speech TTS object. ", Win32::OLE->LastError(), "\n\n";
  35. return;
  36. }
  37. # print "Registering the MS TTS object\n";
  38. $VTxt->Register("Local PC", "perl voice_text.pm");
  39. # print "Setting speed\n";
  40. # $VTxt->{Enabled} = 1;
  41. # my $speed_old = $VTxt->{'Speed'};
  42. }
  43. return $VTxt;
  44. }
  45. sub speak_text {
  46. my(%parms) = @_;
  47. my $pgm_root = $main::Pgm_Root;
  48. $parms{text} = force_pronounce($parms{text}) if %pronouncable;
  49. unless ($VTxt or $VV_TTS or $VTxt_festival or $ViaVoiceTTS) {
  50. unless ($main::config_parms{voice_text}) {
  51. print "Can not speak. mh.ini entry for voice_text is disabled. Phrase=$parms{text}\n";
  52. } else {
  53. print "Can not speak. Voice_Text object failed to create. Phrase=$parms{text}\n";
  54. }
  55. return;
  56. }
  57. if ($VTxt_festival) {
  58. #<SABLE>
  59. #<SPEAKER NAME="male1">
  60. #<VOLUME LEVEL="loud">
  61. #<RATE SPEED="-10%">
  62. # text
  63. #</RATE>
  64. #</VOLUME>
  65. #</SPEAKER>
  66. #</SABLE>
  67. if ($parms{voice} or $parms{volume} or $parms{rate}) {
  68. my $prefix = qq[<SABLE>];
  69. my $suffix = qq[</SABLE>];
  70. if ($parms{voice}) {
  71. $prefix .= qq[<SPEAKER NAME="$parms{voice}">];
  72. $suffix = qq[</SPEAKER>] . $suffix;
  73. }
  74. if ($parms{volume}) {
  75. $prefix .= qq[<VOLUME LEVEL="$parms{volume}">];
  76. $suffix = qq[</VOLUME>]. $suffix;
  77. }
  78. if ($parms{rate}) {
  79. $prefix .= qq[<RATE SPEED="$parms{rate}">];
  80. $suffix = qq[</RATE>] . $suffix;
  81. }
  82. $parms{text} = $prefix . $parms{text} . $suffix;
  83. }
  84. print "Data sent to festival: $parms{text}\n";
  85. set $VTxt_festival qq[(SayText "$parms{text}")];
  86. }
  87. if ($VV_TTS) {
  88. my $self = {};
  89. my $pid = fork;
  90. $SIG{CHLD} = "IGNORE"; # eliminate zombies created by FORK()
  91. if ($pid) {
  92. $$self{pid} = $pid;
  93. } elsif (defined $pid) {
  94. my $vv_tts_arg = "";;
  95. if ($parms{play}) {
  96. if ($parms{play} =~ /^System/ or $parms{play} =~ /^[\\\/]/ or $parms{play} =~ /^\S\:/) {
  97. $vv_tts_arg .= " -play $parms{play} ";
  98. } else {
  99. $vv_tts_arg .= " -play $main::config_parms{sound_dir}/$parms{play} ";
  100. }
  101. }
  102. if ($parms{text}) {
  103. $vv_tts_arg .= " -text '$parms{text}'";
  104. }
  105. print "db start TTS: $VV_TTS $vv_tts_arg\n" if $main::config_parms{debug} eq 'voice';
  106. exec qq[$VV_TTS $vv_tts_arg];
  107. die 'cant exec $VV_TTS';
  108. }
  109. }
  110. if ($ViaVoiceTTS) {
  111. $SIG{CHLD} = "IGNORE"; # eliminate zombies created by FORK()
  112. FORK: # straight out of the book
  113. if (my $pid=fork) { # if forked ok
  114. # Parent's code
  115. print "$parms{text} sent to $pid\n";
  116. } elsif (defined $pid) {
  117. # child's code here
  118. my $prog = <<ProgCode;
  119. use ViaVoiceTTS;
  120. my \$tts = new ViaVoiceTTS();
  121. ViaVoiceTTS::speak \$tts,"$parms{text}";
  122. exit 0;
  123. ProgCode
  124. exec "echo '$prog' | $^X "; # pipe prog to perl
  125. die "ViaVoiceTTS child died"; # This statement should not be reached
  126. } elsif ($! =~ /No more process/) {
  127. # EAGAIN, supposedly recoverable fork error
  128. sleep 2;
  129. redo FORK;
  130. } else {
  131. # weird fork error
  132. die "Can't fork: $!\n";
  133. }
  134. }
  135. if ($VTxt) {
  136. # Turn off vr while speaking ... SB live card will listen while speaking!
  137. # - this doesn't work. TTS does not start right away. Best to poll in Voice_Cmd
  138. # &Voice_Cmd::deactivate;
  139. my(%priority) = ('normal' => hex(200), 'high' => hex(100), 'veryhigh' => hex(80));
  140. my(%type) = ('statement' => hex(1), 'question' => hex(2), 'command' => hex(4),
  141. 'warning' => hex(8), 'reading' => hex(10), 'numbers' => hex(20),
  142. 'spreadsheet' => hex(40));
  143. $parms{type} = 'statement' unless $parms{'type'};
  144. $parms{speed} = 170 unless $parms{'speed'};
  145. $parms{priority} = 'normal' unless $parms{priority};
  146. $priority{$parms{'priority'}} = $parms{'priority'} if $parms{'priority'} =~ /\d+/; # allow for direct parm
  147. # $VTxt->{'Speed'} = $parms{'speed'} if defined $parms{'speed'};
  148. my ($priority, $type, $voice);
  149. $priority = $priority{$parms{'priority'}};
  150. $type = $type{$parms{'type'}};
  151. # Unfortunatly, the voice controls do not work with the
  152. # '95 vintage Centigram text->speech engine :(
  153. # print "priority=$priority type=$type flag=", $priority | $type, "\n";
  154. $voice = qq[\\Vce=Speaker="$parms{voice}"\\] if $parms{voice};
  155. $voice = '' unless $voice;
  156. # $voice = q[\Chr="Angry"\\];
  157. # $voice = q[\\\\Vol=2222\\\\];
  158. # $voice = q[\\VOL=2222\\];
  159. # $voice = q[/Vol=2222/];
  160. # print "text=$parms{'text'}\n";
  161. # print "voice=$voice\n";
  162. # $VTxt->Speak($voice . $parms{'text'}, ($priority | $type));
  163. # $VTxt->Speak($voice . $parms{'text'}, $priority, "Vce=Speaker=Biff")
  164. # print "Sending text to Speak object with voice=$voice type=$type, prioirty=$priority ...";
  165. # $VTxt->Speak($voice . $parms{'text'}, $priority, $voice);
  166. # $VTxt->Speak($voice . $parms{'text'}, $priority);
  167. # $VTxt->Speak($voice . $parms{'text'}, $type, $priority);
  168. print "Voice_Text.pm ms_tts: VTxt=$VTxt text=$parms{'text'}\n" if $main::config_parms{debug} eq 'voice';
  169. $VTxt->Speak($voice . $parms{'text'}, $priority);
  170. # $VTxt->Speak($parms{'text'}, ($priority | $type));
  171. # $VTxt->Speak('Hello \Chr="Angry"\ there. Bruce is \Vce=Speaker=Biff\ a very smart idiot guy.', hex('201'));
  172. # From Agent SpeechOutputTags2zip.doc
  173. # Chr=Normal,Monotone,Whisper
  174. # Ctx=Address,Email,Unknow
  175. # Emp (Emphasizes the next word
  176. # Pau=number (pauses for number of milliseconds from 10 to 2550 (.01 to 2.55 seconds)
  177. # Pit=number (Sets the baseline pitch in hertz (from 50 to 400)
  178. # Rst Resets all tags
  179. # Spd=number Speed from 50 to 250
  180. # Vol=number Volume from 0 to 65535
  181. # More Control tags are at the end of Speeck SDK lowtts.doc
  182. }
  183. }
  184. sub is_speaking {
  185. return unless $VTxt;
  186. return $VTxt->{IsSpeaking};
  187. }
  188. # This has been moved to mh. Leave this stub in so
  189. # we don't break old user code
  190. sub last_spoken {
  191. my ($how_many) = @_;
  192. &main::speak_log_last($how_many);
  193. }
  194. sub read_pronouncable_list {
  195. my($pronouncable_list_file) = @_;
  196. my ($phonemes, $word, $cnt);
  197. open (WORDS, $pronouncable_list_file) or print "\nError, could not find the pronouncable word file $pronouncable_list_file: $!\n";
  198. undef %pronouncable;
  199. while (<WORDS>) {
  200. next if /^\#/;
  201. ($word, $phonemes) = $_ =~ /^(\S+)\s+(.+)\s*$/;
  202. next unless $word;
  203. $cnt++;
  204. $pronouncable{$word} = $phonemes;
  205. }
  206. print "Read $cnt entries from $pronouncable_list_file\n";
  207. close WORDS;
  208. }
  209. sub force_pronounce {
  210. my($phrase) = @_;
  211. print "input phrase is '$phrase'\n" if $main::config_parms{debug} eq 'voice';
  212. for my $word (keys %pronouncable) {
  213. $phrase =~ s/\b$word\b/$pronouncable{$word}/gi;
  214. }
  215. print "output phrase is '$phrase'\n" if $main::config_parms{debug} eq 'voice';
  216. return $phrase;
  217. }
  218. 1;
  219. #
  220. # $Log$
  221. # Revision 1.23 2001/02/24 23:26:40 winter
  222. # - 2.45 release
  223. #
  224. # Revision 1.22 2001/02/04 20:31:31 winter
  225. # - 2.43 release
  226. #
  227. # Revision 1.21 2000/09/09 21:19:11 winter
  228. # - 2.28 release
  229. #
  230. # Revision 1.20 2000/08/19 01:22:36 winter
  231. # - 2.27 release
  232. #
  233. # Revision 1.19 2000/05/06 16:34:32 winter
  234. # - 2.15 release
  235. #
  236. # Revision 1.18 2000/04/09 18:03:19 winter
  237. # - 2.13 release
  238. #
  239. # Revision 1.17 2000/02/20 04:47:55 winter
  240. # -2.01 release
  241. #
  242. # Revision 1.16 2000/01/27 13:44:27 winter
  243. # - update version number
  244. #
  245. # Revision 1.15 2000/01/13 13:39:52 winter
  246. # - added mixer_settings and vvo_stuff (added 2 weeks ago)
  247. #
  248. # Revision 1.12 1999/10/09 20:38:37 winter
  249. # - add max_log_entries check
  250. #
  251. # Revision 1.11 1999/05/30 21:08:55 winter
  252. # - change TDstamp format in log
  253. #
  254. # Revision 1.10 1999/02/21 00:27:17 winter
  255. # - use $OS_win
  256. #
  257. # Revision 1.9 1999/02/04 14:21:28 winter
  258. # - switch to new OLE calls. Add better error checking
  259. #
  260. # Revision 1.8 1999/01/22 02:43:21 winter
  261. # - add Festival support.
  262. #
  263. # Revision 1.7 1999/01/10 02:29:50 winter
  264. # - give better 'tts engine disabled' messages
  265. #
  266. # Revision 1.6 1999/01/09 21:43:14 winter
  267. # - improve ole fail error
  268. #
  269. # Revision 1.5 1999/01/07 01:55:03 winter
  270. # - Limit size of Spoken_Text array
  271. #
  272. # Revision 1.4 1998/12/08 02:26:07 winter
  273. # - add log
  274. #
  275. #