/espeak/doit

https://github.com/dagent/lips · Perl · 172 lines · 120 code · 29 blank · 23 comment · 13 complexity · 7cc67bf8eee498b7f467594477747eef MD5 · raw file

  1. #! /usr/bin/perl
  2. # Espeak wrapper to extract visemes -- see usage() below.
  3. # Author: David A. Gent
  4. # June 2014
  5. $wpm = 80; # slowest espeak words-per-minute; settable with -s option
  6. $wpause = 800; # Milisecond delay between outputting words to espeach
  7. chomp ($PROGNAME = `basename $0`);
  8. sub usage () {
  9. print STDERR <<"+++EOF+++";
  10. usage: $PROGNAME [-w words-per-second] [-p delay] [-D] [-h]
  11. $PROGNAME Starts espeak to accept STDIN for text-to-speak.
  12. Phonemes are mapped to visemes. Speach is done one word at a
  13. time at spoken rate (-w) with a pause (-p) between them
  14. Defaults: $wpm word-per-minute spoken and $wpause milli-seconds
  15. between words;
  16. +++EOF+++
  17. ;
  18. exit;
  19. }
  20. $DEBUG = 0;
  21. select STDERR;
  22. $| = 1;
  23. select STDOUT;
  24. $| = 1;
  25. use Getopt::Std;
  26. use Getopt::Long;
  27. Getopt::Long::Configure("gnu_compat");
  28. GetOptions (
  29. 'debug|D' => \$DEBUG,
  30. 'help|h' => \$help,
  31. 'wpm|w=i' => \$wpm, # Words per minute
  32. 'delay|p=i' => \$wpause, # delay between words (milliseconds).
  33. );
  34. if ( $help ) {
  35. usage();
  36. }
  37. if ( $DEBUG =~ /^$/ ) {
  38. # DEBUG defaults to 0, so this means that there was an option to
  39. # set it
  40. $DEBUG = 1;
  41. }
  42. sub pd {
  43. if ($DEBUG) {
  44. my $errmsg = join " ", @_;
  45. print STDERR "### $errmsg\n";
  46. }
  47. }
  48. $speak_cmd = "/usr/bin/espeak";
  49. #$speak_options = "-s".$wpm." -p1 -ven-us+m7 -x";
  50. $speak_options = "-s".$wpm." -p1 -ven-us -x";
  51. # phoneme/visemes exist here
  52. do "phoneme-viseme.pl";
  53. #%pho_vis_hash = %{mk_phoneme_viseme_hash(\%viseme22, \%espeak_phoneme)};
  54. %pho_vis_hash = %{mk_phoneme_viseme_hash(\%viseme10, \%espeak_phoneme)};
  55. pd("%pho_vis_hash =", keys %pho_vis_hash, values %pho_vis_hash );
  56. # return arrays of phoneme and viseme values currently inputed.
  57. # : matchit(\%phoneme_viseme_hash, $match_string)
  58. # returns references to arrays of matched keys and values
  59. sub matchit {
  60. my %mhash = %{$_[0]} ;
  61. my $mstring = $_[1] ;
  62. my $mre = "(" . join('|', reverse sort(keys(%mhash) )) . ")";
  63. #pd ('$regexp="' . $mre . '"');
  64. #pd ('$mstring="' . $mstring . '"' , "length=" . length($mstring));
  65. my $mkeys = [];
  66. my $mvals = [];
  67. my $mkey;
  68. while ( "$mstring" !~ /^$/ ) {
  69. if ( $mstring =~ /^$mre/ ) {
  70. $mkey = $1;
  71. #pd ('$mkey="' . $mkey . '"' );
  72. push @{$mkeys}, $mkey;
  73. push @{$mvals}, $mhash{$mkey};
  74. $mstring = substr($mstring,length($mkey));
  75. } else {
  76. $mstring = substr($mstring,1);
  77. }
  78. #pd ('$mstring="' . $mstring . '"' , "length=" . length($mstring));
  79. }
  80. return ($mkeys, $mvals);
  81. }
  82. # Wrap the espeak command in a PTY (via socat), since the output is
  83. # buffered when piped!
  84. $speak = "/usr/bin/socat EXEC:" . "\"$speak_cmd $speak_options\"" .
  85. ",pty,echo=0,raw,ctty STDIO";
  86. use IPC::Open3;
  87. use IO::Select;
  88. pd "wpm set to $wpm";
  89. pd "Executing: $speak";
  90. pd "Word pause set to $wpause milliseconds";
  91. my $pid = open3(\*WRITE, \*READ,\*ERROR,"$speak") || die "$!";
  92. my $sel = new IO::Select();
  93. $sel->add(\*READ);
  94. $sel->add(\*ERROR);
  95. print STDERR "\nEnter text\n";
  96. print "0\n";
  97. while( chomp(my $query = <STDIN>) ){
  98. chomp $query;
  99. $query =~ s/^\s+//;
  100. my @query = split /\s+/, $query;
  101. foreach my $say ( @query ) {
  102. #send text to espeak
  103. pd ("Say '$say'.");
  104. print WRITE "$say\n";
  105. foreach my $h ($sel->can_read()) {
  106. #pd("Input buffer found");
  107. my $buf = '';
  108. if ($h eq \*ERROR) {
  109. sysread(ERROR,$buf,4096);
  110. if($buf){
  111. pd("ERROR-> $buf");
  112. }
  113. } else {
  114. sysread(READ,$buf,4096);
  115. chomp $buf;
  116. if($buf){pd "$say = $buf"}
  117. ($matches,$mvals) = matchit(\%pho_vis_hash, $buf);
  118. next if $#{$matches} < 0;
  119. pd ('@matches =[' , join(", ", @{$matches}), ']' );
  120. pd ('@mvals =[' , join(", ", @{$mvals}), ']' );
  121. visemeOut($mvals);
  122. }
  123. }
  124. #pause
  125. select(undef,undef,undef,($wpause/1000));
  126. }
  127. select(undef,undef,undef,($wpause/1000));
  128. print STDERR "\nEnter text\n";
  129. }
  130. # pass viseme hash to stdout formatted for ??
  131. sub visemeOut () {
  132. my @mvals = @{$_[0]};
  133. pd "$#mvals";
  134. my $wait = (60/$wpm)/( $#mvals + 1 );
  135. foreach my $mval (@mvals) {
  136. print "$mval\n";
  137. pd ("pausing for $wait seconds");
  138. select(undef,undef,undef,$wait);
  139. }
  140. print "0\n";
  141. }
  142. # zombie prevention
  143. waitpid($pid, 1);