Update ATIS voice generation scripts
Split voice samples into two separate files (airport and phraseology). Compress voice samples.
This commit is contained in:
parent
2d424062b7
commit
3bf09215b0
7 changed files with 119 additions and 25 deletions
4
scripts/atis/.gitignore
vendored
Normal file
4
scripts/atis/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
*.vlist
|
||||||
|
*.vce
|
||||||
|
*.wav.gz
|
||||||
|
snip/*
|
50
scripts/atis/README
Normal file
50
scripts/atis/README
Normal file
|
@ -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/.
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
#! /usr/bin/perl -w
|
#! /usr/bin/perl -w
|
||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
print <<\EoF;
|
print <<EoF;
|
||||||
Read the atis_lexicon.hxx file and print
|
Read the atis_lexicon.hxx file and print
|
||||||
the vocabulary words ... plus phonetic digits and letters.
|
the vocabulary words ... plus phonetic digits and letters.
|
||||||
|
|
||||||
See also list-airports.pl
|
See also list-airports.pl
|
||||||
|
|
||||||
Typical usage:
|
Typical usage:
|
||||||
(echo "/"
|
FG_ROOT=/home/whatever/fgdata FG_SRC=/home/whatever/flightgear ./atis-lex.pl > phraseology.vlist
|
||||||
FG_ROOT=/games/$whatever/fgd ATIS_ONLY=yes ./list-airports.pl
|
|
||||||
FG_ROOT=/games/$whatever/fgd ./atis-lex.pl) > $whatever.vlist
|
|
||||||
EoF
|
EoF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +22,14 @@ main: {
|
||||||
usage;
|
usage;
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
my $mapfn = "$fgroot/../fgs/src/ATCDCL/atis_lexicon.hxx";
|
my $mapfn = "$ENV{'FG_SRC'}/src/ATCDCL/atis_lexicon.hxx";
|
||||||
my $mapch = Symbol::gensym;
|
my $mapch = Symbol::gensym;
|
||||||
if (!open($mapch, '<', $mapfn)) {
|
if (!open($mapch, '<', $mapfn)) {
|
||||||
print STDERR "Could not open abbreviation file '$mapfn'\n";
|
print STDERR "Could not open abbreviation file '$mapfn'\n";
|
||||||
print STDERR "Maybe you need to set FG_ROOT\n";
|
print STDERR "Maybe you need to set FG_ROOT\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
print "/\n";
|
||||||
while (my $line = <$mapch>) {
|
while (my $line = <$mapch>) {
|
||||||
chomp $line;
|
chomp $line;
|
||||||
if ($line =~ s/^[ \t]*Q[(]//) {
|
if ($line =~ s/^[ \t]*Q[(]//) {
|
||||||
|
@ -76,5 +75,6 @@ whiskey
|
||||||
xray
|
xray
|
||||||
yankee
|
yankee
|
||||||
zulu
|
zulu
|
||||||
|
decimal
|
||||||
EoF
|
EoF
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
my($content, $length);
|
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 = <FILE>) ) {
|
while( chomp($content = <FILE>) ) {
|
||||||
$length = length($content);
|
$length = length($content);
|
||||||
|
|
|
@ -9,14 +9,14 @@ Print airport names, one per line.
|
||||||
Remapping is done by reference to the atis_remap.hxx file.
|
Remapping is done by reference to the atis_remap.hxx file.
|
||||||
|
|
||||||
Typical usage:
|
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
|
EoF
|
||||||
}
|
}
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use Symbol;
|
use Symbol;
|
||||||
my $noparen = 1;
|
|
||||||
|
|
||||||
|
my $noparen = 1;
|
||||||
my $verbose = 0;
|
my $verbose = 0;
|
||||||
my $apt_name = '';
|
my $apt_name = '';
|
||||||
my $lat;
|
my $lat;
|
||||||
|
@ -38,6 +38,7 @@ my $noparen = 1;
|
||||||
|
|
||||||
my $fgroot = $ENV{'FG_ROOT'} || '.';
|
my $fgroot = $ENV{'FG_ROOT'} || '.';
|
||||||
my $atis_only = $ENV{'ATIS_ONLY'} || 0;
|
my $atis_only = $ENV{'ATIS_ONLY'} || 0;
|
||||||
|
my $mapfn = "$ENV{'FG_SRC'}/src/ATCDCL/atis_remap.hxx";
|
||||||
|
|
||||||
sub process_apt {
|
sub process_apt {
|
||||||
if ($atis_only && ! $atis) {
|
if ($atis_only && ! $atis) {
|
||||||
|
@ -60,7 +61,6 @@ sub get_remap {
|
||||||
# Note: in this context, GKI probably stands for Gereja Kristen Indonesia
|
# Note: in this context, GKI probably stands for Gereja Kristen Indonesia
|
||||||
# I guess the church builds lots of airports.
|
# I guess the church builds lots of airports.
|
||||||
|
|
||||||
my $mapfn = "$fgroot/../fgs/src/ATCDCL/atis_remap.hxx";
|
|
||||||
my $mapch = Symbol::gensym;
|
my $mapch = Symbol::gensym;
|
||||||
if (!open($mapch, '<', $mapfn)) {
|
if (!open($mapch, '<', $mapfn)) {
|
||||||
print STDERR "Could not open abbreviation file '$mapfn'\n";
|
print STDERR "Could not open abbreviation file '$mapfn'\n";
|
||||||
|
@ -84,11 +84,16 @@ sub get_remap {
|
||||||
}
|
}
|
||||||
|
|
||||||
main: {
|
main: {
|
||||||
|
if (@ARGV) {
|
||||||
|
usage;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
get_remap;
|
get_remap;
|
||||||
|
|
||||||
my $delim = '-';
|
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;
|
my $inch = Symbol::gensym;
|
||||||
open ($inch, '-|', $incmd)
|
open ($inch, '-|', $incmd)
|
||||||
|| die "Couldn't open pipe from '$incmd'\n";
|
|| die "Couldn't open pipe from '$incmd'\n";
|
||||||
|
|
BIN
scripts/atis/quiet0.500.wav
Normal file
BIN
scripts/atis/quiet0.500.wav
Normal file
Binary file not shown.
|
@ -88,6 +88,7 @@ my %fixup = (
|
||||||
main: {
|
main: {
|
||||||
|
|
||||||
my $skip = 0;
|
my $skip = 0;
|
||||||
|
my $fmtcheck = 1;
|
||||||
my $oneword = 0;
|
my $oneword = 0;
|
||||||
my $gripe = 0;
|
my $gripe = 0;
|
||||||
my $out_bits_sample = 8; ## this is what FGFS expects
|
my $out_bits_sample = 8; ## this is what FGFS expects
|
||||||
|
@ -122,6 +123,10 @@ main: {
|
||||||
$oneword++;
|
$oneword++;
|
||||||
next argx;
|
next argx;
|
||||||
}
|
}
|
||||||
|
if ($arg eq '-nocheck') {
|
||||||
|
$fmtcheck=0;
|
||||||
|
next argx;
|
||||||
|
}
|
||||||
if ($arg =~ '^-') {
|
if ($arg =~ '^-') {
|
||||||
die "Unrecognized option '$arg'\n";
|
die "Unrecognized option '$arg'\n";
|
||||||
}
|
}
|
||||||
|
@ -184,23 +189,31 @@ main: {
|
||||||
|| die "Could not create directory 'snip' : $!\n";
|
|| die "Could not create directory 'snip' : $!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
############## system "/bin/cp nothing.wav t1.wav";
|
my $wav = new Audio::Wav;
|
||||||
my $where = 0;
|
my $waver = $wav -> read("quiet0.500.wav");
|
||||||
my $sample_rate = -1;
|
my $sample_rate = -1;
|
||||||
my $channels = -1;
|
my $channels = -1;
|
||||||
my $bits_sample = -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;
|
my $ii = 0;
|
||||||
|
|
||||||
snipper: for my $thing (sort keys %list) {
|
snipper: for my $thing (sort keys %list) {
|
||||||
$ii++;
|
$ii++;
|
||||||
my $iix = sprintf('%05d', $ii);
|
my $iix = sprintf('%05d', $ii);
|
||||||
my $xfn = "./snip/x$iix";
|
my $xfn = "./snip/x$iix";
|
||||||
|
print( "$xfn\n");
|
||||||
|
|
||||||
my $fraise = lc($thing);
|
my $fraise = lc($thing);
|
||||||
if (exists $fixup{$fraise}) {
|
if (exists $fixup{$fraise}) {
|
||||||
#xxxx print "fixing $fraise\n";
|
#xxxx print "fixing $fraise\n";
|
||||||
$fraise = $fixup{$fraise};
|
$fraise = $fixup{$fraise};
|
||||||
}
|
}
|
||||||
|
|
||||||
## This turns dashes and other funny stuff into spaces
|
## This turns dashes and other funny stuff into spaces
|
||||||
## in the phrase to be processed:
|
## in the phrase to be processed:
|
||||||
$fraise =~ s%[^a-z']+% %gi;
|
$fraise =~ s%[^a-z']+% %gi;
|
||||||
|
@ -223,18 +236,27 @@ main: {
|
||||||
next snipper;
|
next snipper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
my $wav = new Audio::Wav;
|
$ii = 0;
|
||||||
my $waver = $wav -> read("$xfn.wav");
|
snipper: for my $thing (sort keys %list) {
|
||||||
if ($sample_rate < 0) {
|
$ii++;
|
||||||
$sample_rate = ${$waver->details()}{'sample_rate'};
|
my $iix = sprintf('%05d', $ii);
|
||||||
$channels = ${$waver->details()}{'channels'};
|
my $xfn = "./snip/x$iix";
|
||||||
$bits_sample = ${$waver->details()}{'bits_sample'};
|
|
||||||
} else {
|
if ($fmtcheck == 1) {
|
||||||
$sample_rate == ${$waver->details()}{'sample_rate'}
|
my $wav = new Audio::Wav;
|
||||||
&& $channels == ${$waver->details()}{'channels'}
|
my $waver = $wav -> read("$xfn.wav");
|
||||||
&& $bits_sample == ${$waver->details()}{'bits_sample'}
|
if ($sample_rate < 0) {
|
||||||
|| die "audio format not the same: $xfn.wav";
|
$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";
|
my $statcmd = "2>&1 sox $xfn.wav -n stat";
|
||||||
|
@ -268,12 +290,16 @@ main: {
|
||||||
if ($size == 0) {
|
if ($size == 0) {
|
||||||
print STDERR "?Warning! Zero-size audio file for $iix '$thing'\n";
|
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);
|
printf("%s %6.3f %6d '%s'\n", $iix, $vol, $size, $thing);
|
||||||
my $subsize = int($size/2);
|
my $subsize = int($size/2);
|
||||||
printf $index ("%-45s %10d %10d\n", $thing, $where, $subsize);
|
printf $index ("%-45s %10d %10d\n", $thing, $where, $subsize);
|
||||||
$where += $subsize;
|
$where += $subsize;
|
||||||
|
|
||||||
|
|
||||||
my $volume_cmd = sprintf("sox -v %6.3f %s.wav %s.raw",
|
my $volume_cmd = sprintf("sox -v %6.3f %s.wav %s.raw",
|
||||||
$vol*0.9, $xfn, $xfn);
|
$vol*0.9, $xfn, $xfn);
|
||||||
########## print "+ $volume_cmd\n";
|
########## print "+ $volume_cmd\n";
|
||||||
|
@ -300,6 +326,7 @@ main: {
|
||||||
die "Cat command failed: $cat_cmd";
|
die "Cat command failed: $cat_cmd";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Convert RAW to WAVE format
|
||||||
my $wav_cmd = "sox --rate $sample_rate --bits $bits_sample"
|
my $wav_cmd = "sox --rate $sample_rate --bits $bits_sample"
|
||||||
. " --encoding signed-integer"
|
. " --encoding signed-integer"
|
||||||
. " ./snip/everything.raw --rate 8000 --bits $out_bits_sample $out_wav";
|
. " ./snip/everything.raw --rate 8000 --bits $out_bits_sample $out_wav";
|
||||||
|
@ -311,4 +338,12 @@ main: {
|
||||||
if ($?) {
|
if ($?) {
|
||||||
die ".wav command failed: $wav_cmd";
|
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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue