From 17e03e75a43ff75b2cc20ba794b0f4d3131f4a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20H=C3=A4ggqvist?= Date: Sat, 25 Aug 2007 22:00:13 +0000 Subject: [PATCH] Replace the voicebuilding with a perl-based approach. Should greatly speed up building on Cygwin. See more in FS#7646. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14457 a1c6a512-1295-4272-9138-f99709370657 --- docs/MAINTAINERS | 2 +- tools/VOICE_PAUSE.wav | Bin 0 -> 26612 bytes tools/configure | 58 +++--- tools/sapi5_voice_new.vbs | 67 +++++++ tools/voice.pl | 360 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 465 insertions(+), 22 deletions(-) create mode 100644 tools/VOICE_PAUSE.wav create mode 100755 tools/sapi5_voice_new.vbs create mode 100755 tools/voice.pl diff --git a/docs/MAINTAINERS b/docs/MAINTAINERS index 023e1aa6cc..fcf03f74bc 100644 --- a/docs/MAINTAINERS +++ b/docs/MAINTAINERS @@ -290,7 +290,7 @@ Build Tools :scramble: Linus Nielsen Feltzing :descramble: Linus Nielsen Feltzing :mkinfo: Daniel Stenberg -:voice shell scripts: Jonas Häggqvist +:voice perl script: Jonas Häggqvist Install Tools ------------- diff --git a/tools/VOICE_PAUSE.wav b/tools/VOICE_PAUSE.wav new file mode 100644 index 0000000000000000000000000000000000000000..90d07f0ff6743e3d2ef47a1e56378c5b0c313678 GIT binary patch literal 26612 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 x voicesettings-$thislang.sh < Makefile \ -e "${simmagic1}" \ -e "${simmagic2}" \ -e "s,@MANUALDEV@,${manualdev},g" \ + -e "s,@ENCODER@,${ENCODER},g" \ + -e "s,@ENC_OPTS@,${ENC_OPTS},g" \ + -e "s,@TTS_ENGINE@,${TTS_ENGINE},g" \ + -e "s,@TTS_OPTS@,${TTS_OPTS},g" \ < ) \___| < | \_\ ( <_> > < < +' Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +' \/ \/ \/ \/ \/ +' $Id: sapi5_voice.vbs$ +' +' Copyright (C) 2007 Steve Bavin, Jens Arnold, Mesar Hameed +' +' All files in this archive are subject to the GNU General Public License. +' See the file COPYING in the source tree root for full license agreement. +' +' This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +' KIND, either express or implied. +' +'*************************************************************************** +' Purpose: Make a voice clip file for the given text on stdin + +'To be done: +' - Allow user to override voice, speed and/or format (currently uses Control Panel defaults for voice/speed) +' - Voice specific replacements/corrections for pronounciation (this should be at a higher level really) + +Const SSFMCreateForWrite = 3 + +Const SPSF_8kHz16BitMono = 6 +Const SPSF_11kHz16BitMono = 10 +Const SPSF_12kHz16BitMono = 14 +Const SPSF_16kHz16BitMono = 18 +Const SPSF_22kHz16BitMono = 22 +Const SPSF_24kHz16BitMono = 26 +Const SPSF_32kHz16BitMono = 30 +Const SPSF_44kHz16BitMono = 34 +Const SPSF_48kHz16BitMono = 38 + +Dim oSpVoice, oSpFS, nAudioFormat, sText, sOutputFile + +nAudioFormat = SPSF_22kHz16BitMono 'Audio format to use, recommended settings: +'- for AT&T natural voices, use SPSF_32kHz16BitMono +'- for MS voices, use SPSF_22kHz16BitMono + +Set oSpVoice = CreateObject("SAPI.SpVoice") +If Err.Number <> 0 Then + WScript.Echo "Error - could not get SpVoice object. " & _ + "SAPI 5 not installed?" + Err.Clear + WScript.Quit 1 +End If + +While 1 > 0 + sText = WScript.StdIn.ReadLine + sOutputFile = WScript.StdIn.ReadLine + If sOutputFile = "" Then + Set oSpFS = Nothing + Set oSpVoice = Nothing + Set oArgs = Nothing + WScript.Quit 0 + End If + ' WScript.Echo "Saying " + sText + " in " + sOutputFile + Set oSpFS = CreateObject("SAPI.SpFileStream") + oSpFS.Format.Type = nAudioFormat + oSpFS.Open sOutputFile, SSFMCreateForWrite, False + Set oSpVoice.AudioOutputStream = oSpFS + oSpVoice.Speak sText + oSpFS.Close +Wend diff --git a/tools/voice.pl b/tools/voice.pl new file mode 100755 index 0000000000..1635b701f1 --- /dev/null +++ b/tools/voice.pl @@ -0,0 +1,360 @@ +#!/usr/bin/perl -s +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id: +# +# Copyright (C) 2007 Jonas Häggqvist +# +# All files in this archive are subject to the GNU General Public License. +# See the file COPYING in the source tree root for full license agreement. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. + +use strict; +use warnings; +use File::Basename; +use File::Copy; +use Switch; +use vars qw($V $C $t $l $e $E $s $S $i $v); +use IPC::Open3; +use Digest::MD5 qw(md5_hex); + +sub printusage { + print < + Specify which target you want to build voicefile for. Must include + any features that target supports. + + -i= + Numeric target id. Needed for voice building. + + -l= + Specify which language you want to build. Without .lang extension. + + -e= + Which encoder to use for voice strings + + -E= + Which encoder options to use when compressing voice strings. Enclose + in double quotes if the options include spaces. + + -s= + Which TTS engine to use. + + -S= + Options to pass to the TTS engine. Enclose in double quotes if the + options include spaces. + + -v + Be verbose +USAGE +; +} + +# Initialize TTS engine. May return an object or value which will be passed +# to voicestring and shutdown_tts +sub init_tts { + our $verbose; + my ($tts_engine, $tts_engine_opts, $language) = @_; + my $ret = undef; + switch($tts_engine) { + case "festival" { + print("> festival $tts_engine_opts --server\n") if $verbose; + my $pid = open(FESTIVAL_SERVER, "| festival $tts_engine_opts --server > /dev/null 2>&1"); + $ret = *FESTIVAL_SERVER; + $ret = $pid; + $SIG{INT} = sub { kill TERM => $pid; print("foo"); panic_cleanup(); }; + $SIG{KILL} = sub { kill TERM => $pid; print("boo"); panic_cleanup(); }; + } + case "sapi5" { + my $toolsdir = dirname($0); + my $path = `cygpath $toolsdir -a -w`; + chomp($path); + $path = $path . "\\sapi5_voice_new.vbs $language $tts_engine_opts"; + $path =~ s/\\/\\\\/g; + print("> cscript /B $path\n") if $verbose; + my $pid = open(F, "| cscript /B $path"); + $ret = *F; + $SIG{INT} = sub { print($ret "\r\n\r\n"); panic_cleanup(); }; + $SIG{KILL} = sub { print($ret "\r\n\r\n"); panic_cleanup(); }; + } + } + return $ret; +} + +# Shutdown TTS engine if necessary. +sub shutdown_tts { + my ($tts_engine, $tts_object) = @_; + switch($tts_engine) { + case "festival" { + # Send SIGTERM to festival server + kill TERM => $tts_object; + } + case "sapi5" { + print($tts_object "\r\n\r\n"); + close($tts_object); + } + } +} + +# Apply corrections to a voice-string to make it sound better +sub correct_string { + our $verbose; + my ($string, $language, $tts_engine) = @_; + my $orig = $string; + switch($language) { + # General for all engines and languages (perhaps - just an example) + $string =~ s/USB/U S B/; + + case ("deutsch") { + switch($tts_engine) { + $string =~ s/alphabet/alfabet/; + $string =~ s/alkaline/alkalein/; + $string =~ s/ampere/amper/; + $string =~ s/byte(s?)\b/beit$1/; + $string =~ s/\bdezibel\b/de-zibell/; + $string =~ s/energie\b/ener-gie/; + $string =~ s/\bflash\b/fläsh/g; + $string =~ s/\bfirmware(s?)\b/firmwer$1/; + $string =~ s/\bid3 tag\b/id3 täg/g; # can't just use "tag" here + $string =~ s/\bloudness\b/laudness/; + $string =~ s/\bnumerisch\b/numehrisch/; + $string =~ s/\brücklauf\b/rück-lauf/; + $string =~ s/\bsuchlauf\b/such-lauf/; + } + } + } + if ($orig ne $string) { + printf("%s -> %s\n", $orig, $string) if $verbose; + } + return $string; +} + +# Produce a wav file of the text given +sub voicestring { + our $verbose; + my ($string, $output, $tts_engine, $tts_engine_opts, $tts_object) = @_; + my $cmd; + printf("Generate \"%s\" with %s in file %s\n", $string, $tts_engine, $output) if $verbose; + switch($tts_engine) { + case "festival" { + # festival_client lies to us, so we have to do awful soul-eating + # work with IPC::open3() + $cmd = "festival_client --server localhost --otype riff --ttw --output \"$output\""; + print("> $cmd\n") if $verbose; + # Open command, and filehandles for STDIN, STDOUT, STDERR + my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd); + # Put the string to speak into STDIN and close it + print(CMD_IN $string); + close(CMD_IN); + # Read all output from festival_client (because it LIES TO US) + while () { + } + close(CMD_OUT); + close(CMD_ERR); + } + case "flite" { + $cmd = "flite $tts_engine_opts -t \"$string\" \"$output\""; + print("> $cmd\n") if $verbose; + `$cmd`; + } + case "espeak" { + # xxx: $tts_engine_opts isn't used + $cmd = "espeak $tts_engine_opts -w $output"; + print("> $cmd\n") if $verbose; + open(ESPEAK, "| $cmd"); + print ESPEAK $string . "\n"; + close(ESPEAK); + } + case "sapi5" { + print($tts_object sprintf("%s\r\n%s\r\n", $string, $output)); + } + } +} + +# Encode a wav file into the given destination file +sub encodewav { + our $verbose; + my ($input, $output, $encoder, $encoder_opts) = @_; + printf("Encode \"%s\" with %s in file %s\n", $input, $encoder, $output) if $verbose; + switch ($encoder) { + case 'lame' { + my $cmd = "lame $encoder_opts \"$input\" \"$output\""; + print("> $cmd\n") if $verbose; + `lame $encoder_opts "$input" "$output"`; + `$cmd`; + } + case 'vorbis' { + `oggenc $encoder_opts "$input" -o "$output"`; + } + case 'speexenc' { + `speexenc $encoder_opts "$input" "$output"`; + } + } +} + +sub wavtrim { + our $verbose; + my ($file) = @_; + my $cmd = dirname($0) . "/wavtrim \"$file\""; + print("> $cmd\n") if $verbose; + `$cmd`; +} + +# Run genlang and create voice clips for each string +sub generateclips { + our $verbose; + my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_; + my $genlang = dirname($0) . '/genlang'; + my $english = dirname($0) . '/../apps/lang/english.lang'; + my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang'; + my $id = ''; + my $voice = ''; + my $cmd = "$genlang -o -t=$target -e=$english $langfile 2>/dev/null"; + my $pool_file; + open(VOICEFONTIDS, "> voicefontids"); + my $i = 0; + + my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language); + print("Generating voice clips"); + print("\n") if $verbose; + for (`$cmd`) { + my $line = $_; + print(VOICEFONTIDS $line); + if ($line =~ /^id: (.*)$/) { + $id = $1; + } + elsif ($line =~ /^voice: "(.*)"$/) { + $voice = $1; + if ($id !~ /^NOT_USED_.*$/ && $voice ne "") { + my $wav = $id . '.wav'; + my $mp3 = $id . '.mp3'; + + # Print some progress information + if (++$i % 10 == 0 and !$verbose) { + print("."); + } + + # Apply corrections to the string + $voice = correct_string($voice); + + # If we have a pool of snippes, see if the string exists there first + if (defined($ENV{'POOL'})) { + $pool_file = sprintf("%s/%s-%s-%s.mp3", $ENV{'POOL'}, md5_hex($voice), $language, $tts_engine); + if (-f $pool_file) { + printf("Re-using %s (%s) from pool\n", $id, $voice) if $verbose; + copy($pool_file, $mp3); + } + } + + # Don't generate MP3 if it already exists (probably from the POOL) + if (! -f $mp3) { + if ($id eq "VOICE_PAUSE") { + print("Use distributed $wav\n") if $verbose; + copy(dirname($0)."/VOICE_PAUSE.wav", $wav); + } + else { + voicestring($voice, $wav, $tts_engine, $tts_engine_opts, $tts_object); + wavtrim($wav, 500); # 500 seems to be a reasonable default for now + } + + encodewav($wav, $mp3, $encoder, $encoder_opts); + if (defined($ENV{'POOL'})) { + copy($mp3, $pool_file); + } + unlink($wav); + } + $voice = ""; + $id = ""; + } + } + } + print("\n"); + close(VOICEFONTIDS); + shutdown_tts($tts_engine, $tts_object); +} + +# Assemble the voicefile +sub createvoice { + our $verbose; + my ($language, $target_id) = @_; + my $voicefont = dirname($0) . '/voicefont'; + my $outfile = ""; + my $i = 0; + do { + $outfile = sprintf("%s%s.voice", $language, ($i++ == 0 ? '' : '-'.$i)); + } while (-f $outfile); + printf("Saving voice file to %s\n", $outfile) if $verbose; + my $cmd = "$voicefont 'voicefontids' $target_id ./ $outfile"; + print("> $cmd\n") if $verbose; + my $output = `$cmd`; + print($output) if $verbose; +} + +sub deletemp3s() { + for (glob('*.mp3')) { + unlink($_); + } + for (glob('*.wav')) { + unlink($_); + } +} + +sub panic_cleanup { + deletemp3s(); + die "moo"; +} + +# Check parameters +my $printusage = 0; +unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; } +if (defined($V)) { + unless (defined($t)) { print("Missing -t argument\n"); $printusage = 1; } + unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; } + unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; } +} +elsif (defined($C)) { + unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; } +} +unless (defined($e)) { print("Missing -e argument\n"); $printusage = 1; } +unless (defined($E)) { print("Missing -E argument\n"); $printusage = 1; } +unless (defined($s)) { print("Missing -s argument\n"); $printusage = 1; } +unless (defined($S)) { print("Missing -S argument\n"); $printusage = 1; } +if ($printusage == 1) { printusage(); exit 1; } + +$SIG{INT} = \&panic_cleanup; +$SIG{KILL} = \&panic_cleanup; + +if (defined($v) or defined($ENV{'V'})) { + our $verbose = 1; +} + + +# Do what we're told +if ($V == 1) { + printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n", + $t, $l, $e, $E, $s, $S); + generateclips($l, $t, $e, $E, $s, $S); + createvoice($l, $i); + deletemp3s(); +} +elsif ($C) { + # xxx: Implement .talk clip generation +} +else { + printusage(); + exit 1; +}