From 3bf09215b0ba1cf8775a2059d4e094289c885654 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sat, 13 Oct 2012 01:27:52 +0200 Subject: [PATCH] Update ATIS voice generation scripts Split voice samples into two separate files (airport and phraseology). Compress voice samples. --- scripts/atis/.gitignore | 4 +++ scripts/atis/README | 50 ++++++++++++++++++++++++++ scripts/atis/atis-lex.pl | 10 +++--- scripts/atis/find_nonUTF8.pl | 2 +- scripts/atis/list-airports.pl | 13 ++++--- scripts/atis/quiet0.500.wav | Bin 0 -> 16046 bytes scripts/atis/synth.pl | 65 ++++++++++++++++++++++++++-------- 7 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 scripts/atis/.gitignore create mode 100644 scripts/atis/README create mode 100644 scripts/atis/quiet0.500.wav diff --git a/scripts/atis/.gitignore b/scripts/atis/.gitignore new file mode 100644 index 000000000..4a675de98 --- /dev/null +++ b/scripts/atis/.gitignore @@ -0,0 +1,4 @@ +*.vlist +*.vce +*.wav.gz +snip/* diff --git a/scripts/atis/README b/scripts/atis/README new file mode 100644 index 000000000..e5d484b41 --- /dev/null +++ b/scripts/atis/README @@ -0,0 +1,50 @@ +The ATIS Voice Generation HowTo +------------------------------- + +Required packages / installation hints by J. Denker +--------------------------------------------------- + cpan Audio::Wav + apt-get install festival mbrola sox festlex-oald + cd \$tars + wget http://tcts.fpms.ac.be/synthesis/mbrola/dba/en1/en1-980910.zip + wget http://www.cstr.ed.ac.uk/downloads/festival/1.95/festvox_en1.tar.gz + cd /usr/share/festival/voices/english + mkdir en1_mbrola + cd en1_mbrola + unzip \$tars/en1-980910.zip + cd /usr/share/festival + mkdir lib + cd lib + ln -s ../voices ./ + cd /usr/share + tar -xpzvf \$tars/festvox_en1.tar.gz + +Generating Voice Files +---------------------- + + 1. Configure paths to fgdata and flightgear sources + export FG_ROOT=/home/whatever/fgdata + export FG_SRC=/home/whatever/flightgear + + 2. Create phraseology word list + ./atis-lex.pl > phraseology.vlist + + 3. Create airport word list + export ATIS_ONLY=yes + ./list-airports.pl | ./words_per_line.sh > airports.vlist + + 4. Check for and fix non-UTF8 encoded airport names + ./find_nonUTF8.pl + + 5. Generate phraseology voice file + ./synth.pl phraseology.vlist phraseology.vce phraseology.wav + + 6. Generate airport voice file + ./synth.pl airports.vlist airports.vce airports.wav + + 7. Install *.vce and *.wav.gz files in fgdata: + cp phraseology.vce $(FG_ROOT)/ATC/voices/default/. + cp phraseology.wav.gz $(FG_ROOT)/ATC/voices/default/. + cp airports.vce $(FG_ROOT)/ATC/voices/default/. + cp airports.wav.gz $(FG_ROOT)/ATC/voices/default/. + diff --git a/scripts/atis/atis-lex.pl b/scripts/atis/atis-lex.pl index 583080e13..701f1c673 100755 --- a/scripts/atis/atis-lex.pl +++ b/scripts/atis/atis-lex.pl @@ -1,16 +1,14 @@ #! /usr/bin/perl -w sub usage { - print <<\EoF; + print < $whatever.vlist + FG_ROOT=/home/whatever/fgdata FG_SRC=/home/whatever/flightgear ./atis-lex.pl > phraseology.vlist EoF } @@ -24,13 +22,14 @@ main: { usage; exit; } - my $mapfn = "$fgroot/../fgs/src/ATCDCL/atis_lexicon.hxx"; + my $mapfn = "$ENV{'FG_SRC'}/src/ATCDCL/atis_lexicon.hxx"; my $mapch = Symbol::gensym; if (!open($mapch, '<', $mapfn)) { print STDERR "Could not open abbreviation file '$mapfn'\n"; print STDERR "Maybe you need to set FG_ROOT\n"; exit(1); } + print "/\n"; while (my $line = <$mapch>) { chomp $line; if ($line =~ s/^[ \t]*Q[(]//) { @@ -76,5 +75,6 @@ whiskey xray yankee zulu +decimal EoF } diff --git a/scripts/atis/find_nonUTF8.pl b/scripts/atis/find_nonUTF8.pl index a5cf22ebc..dcd45cf73 100755 --- a/scripts/atis/find_nonUTF8.pl +++ b/scripts/atis/find_nonUTF8.pl @@ -2,7 +2,7 @@ my($content, $length); -open(FILE, "< atis.list") || die "Unable to open file small. <$!>\n"; +open(FILE, "< airports.vlist") || die "Unable to open file small. <$!>\n"; while( chomp($content = ) ) { $length = length($content); diff --git a/scripts/atis/list-airports.pl b/scripts/atis/list-airports.pl index a431fca68..347b92842 100755 --- a/scripts/atis/list-airports.pl +++ b/scripts/atis/list-airports.pl @@ -9,14 +9,14 @@ Print airport names, one per line. Remapping is done by reference to the atis_remap.hxx file. Typical usage: - FG_ROOT=whatever ATIS_ONLY=yes ./list-airports.pl | words_per_line.sh > atis.list + FG_ROOT=whatever FG_SRC=whatever ATIS_ONLY=yes ./list-airports.pl | ./words_per_line.sh > airports.vlist EoF } use strict; use Symbol; -my $noparen = 1; + my $noparen = 1; my $verbose = 0; my $apt_name = ''; my $lat; @@ -38,6 +38,7 @@ my $noparen = 1; my $fgroot = $ENV{'FG_ROOT'} || '.'; my $atis_only = $ENV{'ATIS_ONLY'} || 0; + my $mapfn = "$ENV{'FG_SRC'}/src/ATCDCL/atis_remap.hxx"; sub process_apt { if ($atis_only && ! $atis) { @@ -60,7 +61,6 @@ sub get_remap { # Note: in this context, GKI probably stands for Gereja Kristen Indonesia # I guess the church builds lots of airports. - my $mapfn = "$fgroot/../fgs/src/ATCDCL/atis_remap.hxx"; my $mapch = Symbol::gensym; if (!open($mapch, '<', $mapfn)) { print STDERR "Could not open abbreviation file '$mapfn'\n"; @@ -84,11 +84,16 @@ sub get_remap { } main: { + if (@ARGV) { + usage; + exit; + } get_remap; my $delim = '-'; - my $incmd = 'zcat /games/sport/fgd/Airports/apt.dat.gz'; + my $fgroot = $ENV{'FG_ROOT'} || 0; + my $incmd = "zcat $fgroot/Airports/apt.dat.gz"; my $inch = Symbol::gensym; open ($inch, '-|', $incmd) || die "Couldn't open pipe from '$incmd'\n"; diff --git a/scripts/atis/quiet0.500.wav b/scripts/atis/quiet0.500.wav new file mode 100644 index 0000000000000000000000000000000000000000..bceb4e6262895baba4adb8b9337d598ddef54104 GIT binary patch literal 16046 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 F{~ywO)hz%3 literal 0 HcmV?d00001 diff --git a/scripts/atis/synth.pl b/scripts/atis/synth.pl index 1cc0d2223..86cbf6764 100755 --- a/scripts/atis/synth.pl +++ b/scripts/atis/synth.pl @@ -88,6 +88,7 @@ my %fixup = ( main: { my $skip = 0; + my $fmtcheck = 1; my $oneword = 0; my $gripe = 0; my $out_bits_sample = 8; ## this is what FGFS expects @@ -122,6 +123,10 @@ main: { $oneword++; next argx; } + if ($arg eq '-nocheck') { + $fmtcheck=0; + next argx; + } if ($arg =~ '^-') { die "Unrecognized option '$arg'\n"; } @@ -184,23 +189,31 @@ main: { || die "Could not create directory 'snip' : $!\n"; } -############## system "/bin/cp nothing.wav t1.wav"; - my $where = 0; + my $wav = new Audio::Wav; + my $waver = $wav -> read("quiet0.500.wav"); my $sample_rate = -1; my $channels = -1; my $bits_sample = -1; + $sample_rate = ${$waver->details()}{'sample_rate'}; + $channels = ${$waver->details()}{'channels'}; + $bits_sample = ${$waver->details()}{'bits_sample'}; + +############## system "/bin/cp nothing.wav t1.wav"; + my $where = 0; my $ii = 0; + snipper: for my $thing (sort keys %list) { $ii++; my $iix = sprintf('%05d', $ii); my $xfn = "./snip/x$iix"; + print( "$xfn\n"); my $fraise = lc($thing); if (exists $fixup{$fraise}) { #xxxx print "fixing $fraise\n"; $fraise = $fixup{$fraise}; } - + ## This turns dashes and other funny stuff into spaces ## in the phrase to be processed: $fraise =~ s%[^a-z']+% %gi; @@ -223,18 +236,27 @@ main: { next snipper; } } + } - my $wav = new Audio::Wav; - my $waver = $wav -> read("$xfn.wav"); - if ($sample_rate < 0) { - $sample_rate = ${$waver->details()}{'sample_rate'}; - $channels = ${$waver->details()}{'channels'}; - $bits_sample = ${$waver->details()}{'bits_sample'}; - } else { - $sample_rate == ${$waver->details()}{'sample_rate'} - && $channels == ${$waver->details()}{'channels'} - && $bits_sample == ${$waver->details()}{'bits_sample'} - || die "audio format not the same: $xfn.wav"; + $ii = 0; + snipper: for my $thing (sort keys %list) { + $ii++; + my $iix = sprintf('%05d', $ii); + my $xfn = "./snip/x$iix"; + + if ($fmtcheck == 1) { + my $wav = new Audio::Wav; + my $waver = $wav -> read("$xfn.wav"); + if ($sample_rate < 0) { + $sample_rate = ${$waver->details()}{'sample_rate'}; + $channels = ${$waver->details()}{'channels'}; + $bits_sample = ${$waver->details()}{'bits_sample'}; + } else { + $sample_rate == ${$waver->details()}{'sample_rate'} + && $channels == ${$waver->details()}{'channels'} + && $bits_sample == ${$waver->details()}{'bits_sample'} + || die "audio format not the same: $xfn.wav"; + } } my $statcmd = "2>&1 sox $xfn.wav -n stat"; @@ -268,12 +290,16 @@ main: { if ($size == 0) { print STDERR "?Warning! Zero-size audio file for $iix '$thing'\n"; } + + if ($vol > 20) { + ## unreasonable volume, happens with 'silent' files + $vol = 0; + } printf("%s %6.3f %6d '%s'\n", $iix, $vol, $size, $thing); my $subsize = int($size/2); printf $index ("%-45s %10d %10d\n", $thing, $where, $subsize); $where += $subsize; - my $volume_cmd = sprintf("sox -v %6.3f %s.wav %s.raw", $vol*0.9, $xfn, $xfn); ########## print "+ $volume_cmd\n"; @@ -300,6 +326,7 @@ main: { die "Cat command failed: $cat_cmd"; } + ## Convert RAW to WAVE format my $wav_cmd = "sox --rate $sample_rate --bits $bits_sample" . " --encoding signed-integer" . " ./snip/everything.raw --rate 8000 --bits $out_bits_sample $out_wav"; @@ -311,4 +338,12 @@ main: { if ($?) { die ".wav command failed: $wav_cmd"; } + + ## Compress WAVE file + my $gz_cmd = "gzip -f $out_wav"; + my $gz_handle = Symbol::gensym; + open ($gz_handle, '|-', $gz_cmd) + || die "Couldn't open pipe to command '$gz_cmd'\n"; + close $gz_handle; + system("rm snip/*; rmdir snip"); } -- 2.39.5