2 # Portions Copyright 2003 Sun Microsystems, Inc.
3 # Portions Copyright 1999-2003 Language Technologies Institute,
4 # Carnegie Mellon University.
5 # All Rights Reserved. Use is subject to license terms.
7 # See the file "license.terms" for information on usage and
8 # redistribution of this file, and for a DISCLAIMER OF ALL
12 echo "Usage: $0 <voicedir> [lpc | sts | mcep | idx | install | compile]"
14 echo "Converts a festvox voice into FreeTTS format."
16 echo "--help Show this message."
17 echo "<voicedir> The directory containing the festvox voice data."
18 echo " This directory must have a wav/ subdirectory."
19 echo "lpc,sts,mcep,... The second parameter may explicitly run an"
20 echo " individual stage of the conversion process."
22 echo "The ESTDIR environment variable must point to the directory"
23 echo " containing a compiled version of the Edinbourough Speech Tools."
24 echo "festival, ant, java, and javac must be in your path."
26 echo "Running with no second parameter will run the stages in order:"
27 echo " (lpc,sts,mcep,idx,install,compile)."
28 echo "Note that some stages may rely on the execution of previous stages."
30 echo "It is recommended to execute the conversion process without"
31 echo " the second parameter."
35 if [ "$1" = "--help" ] || [ "$1" = "-h" ] || [ "$1" = "-help" ]; then
39 if [ -d "$1" ] && [ -d "$1/wav" ]; then
45 . $VOICEDIR/etc/voice.defs
47 # Description of freetts-specific properties. Try to read them
48 # from voice dir, or assume default values. This is only needed
49 # for the "install" and "compile" steps.
50 if [ -e "$VOICEDIR/etc/freetts.properties" ]; then
51 . $VOICEDIR/etc/freetts.properties
57 VP_DESCRIPTION="description not available"
58 VP_FULL_NAME="$FV_VOICENAME"
61 VOICETARGETBASE="com/sun/speech/freetts"
65 if [ "$2" = "compile" ]; then
66 if [ "$FV_TYPE" = "diphone" ]; then
67 ant -Ddiphone_voice=$VP_FULL_NAME -Duser_voice_base_path=$VOICETARGETBASE/$LOCALEPATH -find build.xml
68 elif [ "$FV_TYPE" = "ldom" ] || [ "$FV_TYPE" = "clunits" ]; then
69 ant -Dclunit_voice=$VP_FULL_NAME -Duser_voice_base_path=$VOICETARGETBASE/$LOCALEPATH -find build.xml
74 if [ ! "$ESTDIR" ]; then
75 echo "environment variable ESTDIR is unset"
76 echo "set it to your local speech tools directory e.g."
77 echo ' bash$ export ESTDIR=/home/<username>/projects/speech_tools/'
79 echo ' csh% setenv ESTDIR /home/<username>/projects/speech_tools/'
84 if [ ! -f $VOICEDIR/etc/voice.defs ]; then
85 echo "Can't find $VOICEDIR/etc/voice.defs file"
86 echo "don't know what voice to convert"
88 echo "If the voice directory is correct, you could try"
89 echo " festvox/src/general/guess_voice_defs to generate it."
91 echo "Setup for conversion of $1 to flite FAILED"
96 if ! festival --version; then
98 echo "ERROR: festival not in path."
103 if ! java -version >/dev/null 2>/dev/null || ! javac -help 2>/dev/null; then
105 echo "ERROR: java and javac must be in path."
110 if ! ant -version; then
112 echo "ERROR: ant not in path."
119 if [ "$2" = "" ]; then
121 # perform each step individually
122 if ! $0 $VOICEDIR lpc; then
125 if ! $0 $VOICEDIR sts; then
128 if [ "$FV_TYPE" != "diphone" ]
130 if ! $0 $VOICEDIR mcep; then
134 if ! $0 $VOICEDIR idx; then
138 if ! $0 $VOICEDIR "install"; then
142 if ! $0 $VOICEDIR compile; then
147 echo "Conversion process complete"
150 # The scheme and java files should be in the same directory as this script
151 HELPERDIR=`dirname $0`
152 # Make sure that HELPERDIR contains an absolute path:
153 echo $HELPERDIR | grep "^/" > /dev/null || HELPERDIR=`pwd`/$HELPERDIR
155 # This assumes that FreeTTS is configured with this directory structure
156 FREETTSDIR="$HELPERDIR/../.."
158 # We need some files from the ArcticToFreeTTS directory...
159 ARCTICDIR="$FREETTSDIR/tools/ArcticToFreeTTS"
161 #This is where some temperary files are generated as well as the final voice
162 OUTDIR=$VOICEDIR/FreeTTS
163 mkdir $OUTDIR >/dev/null 2>/dev/null
165 (cd $ARCTICDIR; mkdir -p classes; cd src; javac -d ../classes *.java)
167 if [ "$2" = "lpc" ]; then
168 echo Creating lpc files
169 mkdir -p $VOICEDIR/lpc
171 bin/make_lpc wav/*.wav
174 echo Creating lpc/lpc.params
175 for file in $VOICEDIR/lpc/*.lpc; do
176 $ESTDIR/bin/ch_track -otype est_ascii $file
177 done | sed '1,/EST_Header_End/d' |
178 awk 'BEGIN {min=0; max=0;} {
179 for (i=4; i<=NF; i++) {
180 if ($i < min) min = $i;
181 if ($i > max) max = $i;
184 printf("LPC_MIN=%f\n",min);
185 printf("LPC_MAX=%f\n",max);
186 printf("LPC_RANGE=%f\n",max-min);
187 }' > $VOICEDIR/lpc/lpc.params
191 if [ "$2" = "sts" ]; then
192 if [ "$FV_TYPE" = "diphone" ]; then
193 # need to create scheme-formatted sts files for diphones
194 echo "Finding STS files"
195 . $VOICEDIR/lpc/lpc.params
197 mkdir $VOICEDIR/sts 2>/dev/null
200 CLASSFILES="FindSTS.class LPC.class STS.class Wave.class Utility.class"
203 jar -cf FindSTS.jar $CLASSFILES
204 rm -f $CLASSFILES 2>/dev/null)
206 for f in $VOICEDIR/lpc/*.lpc; do
207 fname=`basename $f .lpc`
209 java -cp "$HELPERDIR/FindSTS.jar" FindSTS $LPC_MIN $LPC_RANGE $f \
210 $VOICEDIR/wav/$fname.wav $VOICEDIR/sts/$fname.sts
213 # create STS files in the same format as for ARCTIC voices for clunits
214 # and limited domain voices
216 echo "Creating short term signal (STS) files in sts/*.sts"
218 java -cp $ARCTICDIR/classes FindSTS \
219 `find wav -type f | cut -f2 -d/ | cut -f1 -d.`
224 if [ "$2" = "mcep" ]; then
225 # MCEP coefficients are not used for diphones
226 echo Creating mcep/mcep.params and converting mcep files to text
227 for file in $VOICEDIR/mcep/*.mcep; do
229 $ESTDIR/bin/ch_track -otype est_ascii $file > $file.txt
231 done | sed '1,/EST_Header_End/d' |
232 awk 'BEGIN {min=0; max=0;} {
233 for (i=4; i<=NF; i++) {
234 if ($i < min) min = $i;
235 if ($i > max) max = $i;
238 printf("MCEP_MIN=%f\n",min);
239 printf("MCEP_MAX=%f\n",max);
240 printf("MCEP_RANGE=%f\n",max-min);
241 }' > $VOICEDIR/mcep/mcep.params
245 echo Creating unit index
247 echo Creating $OUTDIR/misc.txt
249 festvox/$FV_FULLVOICENAME.scm \
250 $ARCTICDIR/scheme/dump_misc.scm \
251 "(begin (voice_${FV_FULLVOICENAME}) (dump_misc))" > \
254 # UnitDatabase outputs its own info...
255 java -cp $ARCTICDIR/classes UnitDatabase \
256 festival/clunits/${FV_VOICENAME}.catalogue \
257 `find wav -type f | cut -f2 -d/ | cut -f1 -d.`
259 echo Creating $OUTDIR/trees.txt
261 festvox/$FV_FULLVOICENAME.scm \
262 $ARCTICDIR/scheme/dump_trees.scm \
263 "(begin (voice_${FV_FULLVOICENAME}) (dump_trees))" > \
266 echo Creating $OUTDIR/weights.txt
268 festvox/$FV_FULLVOICENAME.scm \
269 $ARCTICDIR/scheme/dump_join_weights.scm \
270 "(begin (voice_${FV_FULLVOICENAME}) (dump_join_weights))" > \
273 echo Combining these files into $OUTDIR/$FV_VOICENAME.txt
274 (cd $OUTDIR; cat misc.txt unit_catalog.txt trees.txt unit_index.txt sts.txt mcep.txt weights.txt > $FV_VOICENAME.txt)
280 echo "Building diphone index"
282 sed '1,/EST_Header_End/d' $VOICEDIR/dic/*.est |
283 awk '{printf("( %s )\n",$0)}' >$VOICEDIR/dic/diphidx.unsorted.scm
284 festival --heap 5000000 -b \
285 $HELPERDIR/qsort.scm \
286 '(begin (set! diphindex (load
287 "'$VOICEDIR/dic/diphidx.unsorted.scm'" t))
288 (set! diphindex (qsort diphindex carstring<? carstring=?))
289 (while (not (null? diphindex))
290 (set! x (car diphindex))
291 (format t "( %l %l %l %l %l ) \n"
292 (nth 0 x) (nth 1 x) (nth 2 x) (nth 3 x) (nth 4 x))
293 (set! diphindex (cdr diphindex))
294 ))' > $VOICEDIR/dic/diphidx.scm
296 festival --heap 5000000 -b \
297 $HELPERDIR/FestVoxDiphoneToFreeTTS.scm \
298 '(dump_diphone "'$FV_VOICENAME'" "'$VOICEDIR'"
299 "'$OUTDIR'" "header.txt" "data.txt"
300 "'$VOICEDIR'/dic/diphidx.scm")'
301 # parentheses allow script to only temporarily change to $OUTDIR
303 rm -f README 2>/dev/null
304 rm -f $FV_VOICENAME.txt 2>/dev/null
305 echo "The data for the voice $FV_VOICENAME is stored in" > README
306 echo "$FV_VOICENAME.txt All other files may be ignored." >> README
307 echo "*** Generated by $0 $1 $2" > $FV_VOICENAME.txt
308 echo "*** clunits " `date` >> $FV_VOICENAME.txt
309 cat header.txt data.txt >> $FV_VOICENAME.txt
310 if [ -e "alias.txt" ]; then
311 cat alias.txt >> $FV_VOICENAME.txt
317 if [ "$2" = "idx" ]; then
318 if [ "$FV_TYPE" = "diphone" ]; then
327 echo "Please the number corresponding to the gender of this voice:"
332 echo " Q <Quit>: Abort the conversion process."
335 if [ "$REPLY" = "0" ]; then
337 elif [ "$REPLY" = "1" ]; then
340 elif [ "$REPLY" = "2" ]; then
343 elif [ "$REPLY" = "3" ]; then
346 elif [ "$REPLY" = "Q" ] || [ "$REPLY" = "q" ]; then
358 echo "Please enter the number corresponding to the age of this voice:"
360 echo " 1 Neutral: Voice with an age that is indeterminate."
361 echo " 2 Child: Age roughly up to 12 years."
362 echo " 3 Teenager: Age roughly 13 to 19 years."
363 echo " 4 Younger Adult: Age roughly 20 to 40 years."
364 echo " 5 Middle Adult: Age roughly 40 to 60 years."
365 echo " 6 Older Adult: Age roughly 60 years and up."
366 echo " Q <Quit>: Abort the conversion process."
372 if [ "$REPLY" = "0" ]; then
374 elif [ "$REPLY" = "1" ]; then
377 elif [ "$REPLY" = "2" ]; then
380 elif [ "$REPLY" = "3" ]; then
383 elif [ "$REPLY" = "4" ]; then
384 VP_AGE="YOUNGER_ADULT"
386 elif [ "$REPLY" = "5" ]; then
387 VP_AGE="MIDDLE_ADULT"
389 elif [ "$REPLY" = "6" ]; then
392 elif [ "$REPLY" = "Q" ] || [ "$REPLY" = "q" ]; then
399 if [ "$2" = "install" ]; then
401 VP_ORGANIZATION=$FV_INST
402 if [ "$FV_TYPE" = "diphone" ]; then
403 if ! [ "$FV_LANG" = "us" ]; then
405 echo "This script can only install US/English voices in full."
406 echo "For other languages, manual work will be required to make "
407 echo "the voice usable."
408 echo "Please refer to your documentation for instructions on"
409 echo "how to procede."
412 elif [ "$FV_TYPE" = "ldom" ] || [ "$FV_TYPE" = "clunits" ]; then
413 if [ "$FV_TYPE" = "clunits" ]; then
417 echo "Warning: For US/English voices, this script will default to a full"
418 echo "lexicon. For non US/English voices, no lexicon will be set;"
419 echo "manual work will be required to make the voice usable."
420 echo "If you need to adapt the lexicon settings, you can change"
421 echo "that in the java voice directory after the install"
422 echo "phase is finished."
424 echo "Press <Enter> to continue, or <Ctrl-C> to cancel"
428 echo "Only diphone, clunits, and ldom types are supported by this operation."
434 echo "Do you want to import the festival phoneset into FreeTTS (y/n)?"
437 if [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ] ; then
439 echo Creating $OUTDIR/phoneset.txt
441 festvox/$FV_FULLVOICENAME.scm \
442 $ARCTICDIR/scheme/dump_phoneset.scm \
443 "(begin (voice_${FV_FULLVOICENAME}) (dump_phoneset))" > \
453 echo "Current properties of this voice:"
454 echo " 0 <continue with installation>"
455 echo " 1 Name: '$VP_NAME'"
456 echo " 2 Gender: '$VP_GENDER'"
457 echo " 3 Age: '$VP_AGE'"
458 echo " 4 Description: '$VP_DESCRIPTION'"
459 echo " 5 Full Name: '$VP_FULL_NAME'"
460 echo " 6 Domain: '$VP_DOMAIN'"
461 echo " 7 Organization: '$VP_ORGANIZATION'"
462 echo " 8 Language: '$VP_LOCALE'"
463 echo " 9 Voice base path: '$VOICETARGETBASE'"
464 echo " 10 Debug info: '$DEBUGINFO'"
466 echo " Q <Quit>: Abort the conversion process."
469 echo "Enter the number for the property you would like to change,"
470 echo "'0' if everything looks correct, or 'Q' to exit:"
473 if [ "$REPLY" = "Q" ] || [ "$REPLY" = "q" ]; then
475 elif [ "$REPLY" = "H" ] || [ "$REPLY" = "h" ]; then
482 echo " Name: generally a one-word name by which you want this"
483 echo " voice to be known, such as \"kevin\", \"alan\","
485 echo " Description: a sentence or so that describes this voice."
486 echo " Gender: male, female, or neutral"
487 echo " Age: one of: Neutral, Child, Teenager, Younger Adult,"
488 echo " Middle Adult, Older Adult"
489 echo " Full Name: the name that will be used for the FreeTTS"
490 echo " files for this voice. The Full Name must be unique"
491 echo " name from all other voices in FreeTTS. It is HIGHLY"
492 echo " recommended that you do NOT change this property unless"
493 echo " it conflicts with an existing voice."
494 echo " Domain: the domain for limited domain voices (such as"
495 echo " \"time\" or \"weather\"), otherwise \"general\"."
496 echo " Organization: the organization which recorded the voice,"
497 echo " such as \"sun\" or \"cmu\"."
498 echo " All properties can be changed manually after the conversion"
499 echo " process, but it is easiest to do it now."
501 echo "Press <Enter> to return to the menu."
503 elif [ "$REPLY" = "0" ]; then # only way to exit while loop
504 LOCALEPATH=`echo $VP_LOCALE | sed "s|_|/|g" | tr A-Z a-z`
506 # OK, user agreed to these settings -- let's remember them
507 # for the future (i.e., compile).
509 echo "# Description of this voice for FreeTTS"
510 echo "VP_NAME=\"$VP_NAME\""
511 echo "VP_GENDER=\"$VP_GENDER\""
512 echo "VP_AGE=\"$VP_AGE\""
513 echo "VP_DESCRIPTION=\"$VP_DESCRIPTION\""
514 echo "VP_FULL_NAME=\"$VP_FULL_NAME\""
515 echo "VP_LOCALE=\"$VP_LOCALE\""
516 echo "LOCALEPATH=\"$LOCALEPATH\""
517 echo "VOICETARGETBASE=\"$VOICETARGETBASE\""
518 echo "DEBUGINFO=\"$DEBUGINFO\""
520 ) > $VOICEDIR/etc/freetts.properties
522 VOICETARGETDIR=$FREETTSDIR/$VOICETARGETBASE/$LOCALEPATH
523 if [ -d "$VOICETARGETDIR/$VP_FULL_NAME" ]; then
525 echo "Warning: the voice '$FV_VOICENAME' is already installed"
526 echo "in this version of FreeTTS (in $VOICETARGETDIR)."
527 echo "Please enter the number corresponding to the action you would like to take: "
528 echo " 0 Cancel conversion process"
529 echo " 1 Over-write existing voice"
530 echo " 2 Change your voice's Full Name"
531 echo " (it is recommended to follow a convention similar"
532 echo " to <institution>_<lang/domain>_<name>)"
535 if [ "$REPLY2" = "0" ]; then
537 elif [ "$REPLY2" = "1" ]; then
539 echo "Are you sure you want to over-write the existing"
540 echo "voice? WARNING: May cause permanent loss of"
541 echo "existing voice! (Yes/No/Cancel):"
544 if [ "$REPLY3" = "Y" ] || [ "$REPLY3" = "y" ] \
545 || [ "$REPLY3" = "yes" ] || [ "$REPLY3" = "Yes" ] \
546 || [ "$REPLY3" = "YES" ]; then
548 echo "***** Over-writing existing voice *****"
549 break # exit while loop
553 break # exit while loop
555 elif [ "$REPLY" = "1" ]; then
557 echo "Enter a new name: "
559 elif [ "$REPLY" = "2" ]; then
561 elif [ "$REPLY" = "3" ]; then
563 elif [ "$REPLY" = "4" ]; then
565 echo "Enter a new Description: "
567 elif [ "$REPLY" = "5" ]; then
569 echo "Enter a new Full Name: "
571 elif [ "$REPLY" = "6" ]; then
573 echo "Enter a new domain (\"general\" for unlimited domains) : "
575 elif [ "$REPLY" = "7" ]; then
577 echo "Enter the organization which created this voice: "
579 elif [ "$REPLY" = "8" ]; then
581 echo "Enter the ISO Locale code for the language you are using,"
582 echo "e.g., 'en_US' or 'de': "
584 elif [ "$REPLY" = "9" ]; then
586 echo "Enter the path where to install the voice:"
588 elif [ "$REPLY" = "10" ]; then
590 echo "Do you want to include debug information about unit origins into FreeTTS (y/n)?"
595 # start from a clean slate
596 rm -rf "$VOICETARGETDIR/$VP_FULL_NAME" 2>/dev/null
597 mkdir -p "$VOICETARGETDIR/$VP_FULL_NAME" 2>/dev/null
599 if ! [ -d "$VOICETARGETDIR/$VP_FULL_NAME" ]; then
601 echo "ERROR: Unable to create $VOICETARGETDIR/$VP_FULL_NAME."
605 # java class names should begin with a capital letter
606 VOICEDIRECTORY_CLASS=`echo $VP_NAME | awk '{ print(toupper(substr($0,1,1)) substr($0,2)) }'`"VoiceDirectory"
607 FULL_VOICEDIRECTORY_CLASS=`echo $VOICETARGETBASE/$LOCALEPATH/$VP_FULL_NAME/$VOICEDIRECTORY_CLASS | tr / .`
609 echo "Copyright 2003 Sun Microsystems, Inc."
611 echo "See the file "license.terms" for information on usage and redistribution of"
612 echo "this file, and for a DISCLAIMER OF ALL WARRANTIES."
615 echo "This directory contains a voice imported from FestVox."
616 echo "$VP_FULL_NAME.txt is the text version of the voice data."
617 echo ".bin and .idx files are compiled versions of this file."
618 echo "$VOICEDIRECTORY_CLASS.java is the voice directory which"
619 echo "contains information about the voices (or variations on"
620 echo "voices) that are provided in this directory. By default"
621 echo "the FestVox to FreeTTS conversion utility only puts one"
622 echo "voice in this directory."
624 echo "$VP_FULL_NAME.jar is the file that is created when FreeTTS"
625 echo "is compiled. This jar file will be put in the same directory"
626 echo "as the other FreeTTS jar files. (Generally '<FreeTTS>/lib/')"
627 echo "voice.Manifest is used as the Manifest for the jar file."
629 echo "Please confirm that $VOICEDIRECTORY_CLASS.java and"
630 echo "voice.Manifest contain the correct information."
631 echo "(If you created a ldom voice, it is still configured to use"
632 echo "a full US/English lexicon. You may wish to change that)."
633 ) > "$VOICETARGETDIR/$VP_FULL_NAME/README"
636 cp -f "$OUTDIR/phoneset.txt" "$VOICETARGETDIR/$VP_FULL_NAME/phoneset.txt"
637 cp -f "$OUTDIR/$FV_VOICENAME.txt" "$VOICETARGETDIR/$VP_FULL_NAME/$VP_FULL_NAME.txt"
638 if [ "$DEBUGINFO" = "Y" ] || [ "$DEBUGINFO" = "y" ] ; then
639 cp -f $VOICEDIR/festival/clunits/${FV_VOICENAME}.catalogue $VOICETARGETDIR/$VP_FULL_NAME/${VP_FULL_NAME}.debug
642 echo "Main-Class: $FULL_VOICEDIRECTORY_CLASS" > "$VOICETARGETDIR/$VP_FULL_NAME/voice.Manifest"
643 echo "FreeTTSVoiceDefinition: true" >> "$VOICETARGETDIR/$VP_FULL_NAME/voice.Manifest"
644 if [ "$VP_LOCALE" = "en_US" ]; then
645 echo "Class-Path: cmulex.jar" >> "$VOICETARGETDIR/$VP_FULL_NAME/voice.Manifest"
647 if [ "$FV_TYPE" = "diphone" ]; then
648 if [ "$VP_LOCALE" = "en_US" ]; then
649 VD_TEMPLATE="$HELPERDIR/CMU_USDiphoneTemplate.java.template"
651 VD_TEMPLATE="$HELPERDIR/BaseDiphoneTemplate.java.template"
653 UNIT_DATABASE_CLASS="com.sun.speech.freetts.diphone.DiphoneUnitDatabase"
654 MAKEFILE_EXCLUDE="CLUNITS_ONLY"
656 if [ "$VP_LOCALE" = "en_US" ]; then
657 VD_TEMPLATE="$HELPERDIR/CMU_USClunitTemplate.java.template"
658 elif [ "$FV_TYPE" = "ldom" ]; then
659 VD_TEMPLATE="$HELPERDIR/BaseLdomTemplate.java.template"
661 VD_TEMPLATE="$HELPERDIR/BaseClunitTemplate.java.template"
663 UNIT_DATABASE_CLASS="com.sun.speech.freetts.clunits.ClusterUnitDatabase"
664 MAKEFILE_EXCLUDE="DIPHONE_ONLY"
667 JAVALOCALE=`echo $VP_LOCALE | sed "s/_/\", \"/g"`
668 PACKAGEPATH=`echo $VOICETARGETBASE/$LOCALEPATH | tr / .`
669 # create the voice directory class
670 cat $VD_TEMPLATE | sed "s/%CLASSNAME%/$VOICEDIRECTORY_CLASS/g" \
671 | sed "s/%PATH%/$PACKAGEPATH/g" \
672 | sed "s/%VOICENAME%/$VP_FULL_NAME/g" \
673 | sed "s/%NAME%/$VP_NAME/g" \
674 | sed "s/%GENDER%/$VP_GENDER/g" \
675 | sed "s/%AGE%/$VP_AGE/g" \
676 | sed "s/%DESCRIPTION%/$VP_DESCRIPTION/g" \
677 | sed "s/%DOMAIN%/$VP_DOMAIN/g" \
678 | sed "s/%ORGANIZATION%/$VP_ORGANIZATION/g" \
679 | sed "s/%LOCALE%/$JAVALOCALE/g" \
680 > "$VOICETARGETDIR/$VP_FULL_NAME/$VOICEDIRECTORY_CLASS.java"
682 echo "The voice has been successfully installed in"
683 echo "$VOICETARGETDIR/$VP_FULL_NAME/"