Hi monks
I'm interested in a simple way of getting a Perl (Nant etc) script to announce the result of it's work using the pc loudspeaker, ie. converting an arbitrary text string to voice (text-to-speech synthesis).As simple as : say "hello world".
I've searched CPAN and other repositories (Active state et al) but there seems to be no high level and easily installable Perl module to achieve this functionality, -- at least not for Windows/Win32.
There are several freeware programs that may be run in "command line/batch" mode to achieve the requested "speak" functionality, buth that's overly clunky.
Anyone had the same issue and resolved it?
best regards
allan dystrup
update
Here's a quick hack for a Perl "SAY" program. Compiled to say.exe I can hand it any text (program arg or pipe), and it will speak it...
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
use Speech::Synthesis;
use Getopt::Easy; # Exports: get_options() and %O
my $engine = 'SAPI5'; # SAPI5|'SAPI4'|'MSAgent'|'MacSpeech'|'Festival
+'
my @voices = Speech::Synthesis->InstalledVoices( engine => $engine);
my @avatars = Speech::Synthesis->InstalledAvatars(engine => $engine);
my $ss;
### ===========================================================
### void test_voices(void)
### ===========================================================
sub test_voices {
foreach my $voice (@voices) {
# Construct new Speech::Synthesis object ($ss)
my %params = ( engine => $engine,
avatar => undef,
language => $voice->{language},
voice => $voice->{id},
async => 0
);
my $ss = Speech::Synthesis->new( %params );
# Print Voice info and speak description
print "\n\tId\t=\t" . $voice->{id},
"\n\tName\t=\t" . $voice->{name},
"\n\tVoice\t=\t" . $voice->{description},
"\n\tLang.\t=\t" . $voice->{language},
"\n\tGender\t=\t" . $voice->{gender},
"\n\tAge\t=\t" . $voice->{age};
$ss->speak($voice->{description}|| "test");
}
}
### ===========================================================
### ss set_voice(name)
### ===========================================================
sub set_voice {
my $name = shift || 'Default';
# Build hash of available voices (name->id, cf. test_voices)
my $reg = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Toke
+ns';
my %voices = (
ATTCrystal => $reg . '\ATT-DT-14-Crystal16',
ATTMike => $reg . '\ATT-DT-14-Mike16',
CMUKal => $reg . '\CMUKal',
MSMary => $reg . '\MSMary',
MSMike => $reg . '\MSMike',
MSSam => $reg . '\MSSam',
Default => $reg . '\ATT-DT-14-Crystal16',
);
# lookup name->id, and set $voice_id
my $voice_id = $voices{Default};
foreach my $key (sort keys %voices) {
if ($key =~ /$name/i) { $voice_id = $voices{$key}; last; }
}
# Construct new Speech::Synthesis object ($ss) for $voice_id
my %params = (
engine => $engine,
voice => $voice_id,
async => 0
);
$ss = Speech::Synthesis->new( %params );
}
### ===========================================================
### IO
### ===========================================================
sub is_interactive { # called from shell (1) or via pipe (0) ?
return -t STDIN && -t STDOUT;
}
sub slurp_STDIN { # return piped stream as string
local($/); return <STDIN>;
}
### ===========================================================
### unit test
### ===========================================================
=cut
test_voices();
set_voice('ATTMike');
$ss->speak("hello Mike");
set_voice('ATTCrystal');
$ss->speak("hello Crystal");
=cut
### ===========================================================
### main
### ===========================================================
get_options "v-voice=", "usage: say [-v voice] sentence";
# print Dumper(\%O);
set_voice($O{voice});
my $sentence = is_interactive() ? shift : slurp_STDIN;
$sentence ||= "Please provide a text to speak!";
$ss->speak($sentence);