#! @PERL@
#

$ISIP_HELP_FILE = <<__ISIP_HELP_HERE_FILE__;
name: create_triphone_map
synopsis: create_triphone_map -context <cd/ci> -mono <monophone list> 
    -clist <htk clist>  -models <models text> -output <output file>


descr:  this script converts the HTK's clist to phone list we use in our 
        decoder it outputs a unique index for all the physical triphones 
        and maps all the logical triphones to the physical ones just like 
        HTK does. additional information like number of phones present in
        the nphone definition and the indices of the phones themselves are
        output. each triphone has the following output format:

        x-y+z 3 ind_of_x ind_of_y ind_of_z ind_of_triphone physical_model_ind

example: create_triphone_map.pl -context cd -mono monophones.text 
         -clist triphones.clist -models models.text -output phones.text

options:
 -mono: monophones file
 -context: context dependent or independent models
 -clist: HTK style clustered phones list
 -models: model definition file
 -output: output phone definition file

arguments:
 monophones.text:
 cd: context dependent
 triphones.clist: clustered triphones list
 models.text: physical triphone model definition file
 phones.text: output triphone definition file

man page: none
__ISIP_HELP_HERE_FILE__

# define the program name
#
@tmp = split(/\//, $0);
$ISIP_PROG = pop(@tmp);

# define command line options
#
$CTM_OPT_MONO = "-mono";
$CTM_OPT_CLIST = "-clist";
$CTM_OPT_CONTEXT = "-context";
$CTM_OPT_MODELS = "-models";
$CTM_OPT_OUT = "-output";

# load the command_line source
#
require "$ENV{ISIP_PROTO}/lib/scripts/perl/command_line.pm";

# parse the command line arguments
#
my ($monolist, $clist, $context, $modellist, $output) = command_line(0, $CTM_OPT_MONO, 1, $CTM_OPT_CLIST, 1, $CTM_OPT_CONTEXT, 1, $CTM_OPT_MODELS, 1, $CTM_OPT_OUT, 1);

# error checking of command line arguments
#
if ($monolist eq "") {
    isip_die("monophones file not specified on the command line.\n\ttry the -help option.");
}

if ($clist eq "") {
    isip_die("clist file not specified on the command line.\n\ttry the -help option.");
}

if ($context eq "") {
    isip_die("context not specified on the command line.\n\ttry the -help option.");
}

if ($modellist eq "") {
    isip_die("models file not specified on the command line.\n\ttry the -help option.");
}

if ($output eq "") {
    isip_die("output file not specified on the command line.\n\ttry the -help option.");
}

# open files
# 
open (mono_file, "$monolist") || die "Cannot open file $monolist\n";
open (clist_file, "$clist") || die "Cannot open file $clist\n";
open (mlist_file, "$modellist") || die "Cannot open file $modellist\n";
open (output_file, ">$output") || die "Cannot open file $output:\n";

# define constants
#
$MONOPHONE_SIZE = 1;
$BIPHONE_SIZE = 2;
$TRIPHONE_SIZE = 3;
$NUM_ARGS = 4;
$CI="ci";
$CD="cd";

# define local variables
#
$index = 0;
$tri_index = 2;
$triphone_count = 0;

# read monophone list and index the monophones
#
while (<mono_file>) {    
    chop;
    @temp = split(/\s+/, $_);
    
    # make sure commenst etc are not confused with phones
    #
    if ($#temp == 0 && $temp[0] ne "#") {
	$monophone{$_} = $index;
	$index++;
    }
}

$INDEX="index";
$PHONE="phone";
$flag = 0;
while (<mlist_file>) {
    chop;

    if (/$INDEX\:\s+(\d+)/) {
	$flag = 1;
	$temp_index = $1;	
    }
    if ($flag == 1) {
	if (/$PHONE\:\s+(\S+)/) {	    
	    $triphone_map{$1} = $temp_index;
	    $flag = 0;
	}
    }
}

# read the htk triphone clist and index the triphones so that they match the
# model indices in models.text
#
while (<clist_file>) {
    chop;
    @triphones=split(/\s+/, $_);
    
    # if this is a logical triphone
    #
    if ($#triphones == 1 && $triphones[0] ne "#") {
	
	# if the physical triphone is already defined/indexed
	#
	if (!defined($triphone_map{$triphones[0]})) {
	    $triphone_map{$triphones[0]} = $triphone_map{$triphones[1]};
	    $triphone_count++;
	}
    }

    # if physical model
    #
    elsif ($#triphones == 0 && $triphones[0] =~ /\S+/ && $triphones[0] ne "#"){
	$triphone_count++;
    }    
}	

# print the total number of triphones
#
print output_file "num_phones = $triphone_count\n\n";

# treat context independent mode separately
#
if ($context eq $CI) {

    # print the mapping information
    #
    foreach $key (sort keys(%triphone_map)){

       # print the phone identities and the indices
       #
       $score = $monophone{$key};
       print output_file "$key 1 $monophone{$key} $score $triphone_map{$key}\n";
   }
}

else {

    # print the mapping information
    #
    foreach $key (sort keys(%triphone_map)){

       # for each key find the phonetic content of the triphone
       #
       @phones=split(/\+|\-/,$key);
       $nphone_size{$key} = $#phones + 1;
       print output_file "$key $nphone_size{$key} ";
   
       # if triphone compute index as usual 
       #
       if ($nphone_size{$key} == $TRIPHONE_SIZE) {
	   
	   $score = 0;
	   for ($i = 0; $i <= $#phones; $i = $i + 1) {
	       $score += $monophone{$phones[$i]}*($index**$i);
	   }
   
	   # print the phone identities and the indices
	   #
	   print output_file "$monophone{$phones[0]} $monophone{$phones[1]} $monophone{$phones[2]} $score $triphone_map{$key}\n";
       }
       
       # if biphone compute index accordingly for left context biphone or 
       # right context biphone
       #
       elsif ($nphone_size{$key} == $BIPHONE_SIZE) {
   
	   $score = 0;
   
	   # if left context biphone
	   #
	   if ($key =~ /\-/) {
	       $score = $monophone{$phones[0]} + $monophone{$phones[1]}*$index;
	   }
           
           # else if right context biphone
	   #
	   elsif ($key =~ /\+/) {
	       $score = $monophone{$phones[0]}*$index + 
		   $monophone{$phones[1]}*($index**2);
	   }
   
	   # print the phone identities and the indices
	   #
	   print output_file "$monophone{$phones[0]} $monophone{$phones[1]} $score $triphone_map{$key}\n";
       }
   
       # if monophone compute index as if this is the middle phone of a triphone
       #
       elsif ($nphone_size{$key} == $MONOPHONE_SIZE) {
	   
	   $score = $monophone{$phones[0]}*$index;
	   
	   # print the phone identities and the indices
	   #
	   print output_file "$monophone{$phones[0]} $score $triphone_map{$key}\n";
       }
    }
}
    
# 
# end of script


