--- /dev/null
+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/.
+
#! /usr/bin/perl -w
sub usage {
- print <<\EoF;
+ print <<EoF;
Read the atis_lexicon.hxx file and print
the vocabulary words ... plus phonetic digits and letters.
See also list-airports.pl
Typical usage:
- (echo "/"
- FG_ROOT=/games/$whatever/fgd ATIS_ONLY=yes ./list-airports.pl
- FG_ROOT=/games/$whatever/fgd ./atis-lex.pl) > $whatever.vlist
+ FG_ROOT=/home/whatever/fgdata FG_SRC=/home/whatever/flightgear ./atis-lex.pl > phraseology.vlist
EoF
}
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[(]//) {
xray
yankee
zulu
+decimal
EoF
}
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;
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) {
# 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";
}
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";
main: {
my $skip = 0;
+ my $fmtcheck = 1;
my $oneword = 0;
my $gripe = 0;
my $out_bits_sample = 8; ## this is what FGFS expects
$oneword++;
next argx;
}
+ if ($arg eq '-nocheck') {
+ $fmtcheck=0;
+ next argx;
+ }
if ($arg =~ '^-') {
die "Unrecognized option '$arg'\n";
}
|| 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;
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";
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";
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";
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");
}