#! /usr/bin/perl
#
# Special purpose program for Unix/Linux:
# Read all arguments as Tab Delimited table files with 
# Phoneme data.
#
# Construct a Database table for Center of Gravity values.
#
# Use:
# ./ConstructCoGTables.pl <SpeakerGlob>
#
# --datapath <DataPath> (e.g., ~/NewSLspeech) for an alternative 
#   source of formant files (NOTE: uses <DataPath>/Formants as the
#   actual path)
#
# --tableextension <name> (e.g., 'New') Name added to the table
#   names to distinguish them from the "standard" ones.
#
# --smooth  Use SmoothFormants i.o. formants
#
# This will read in all files from <SpeakerGlob> (e.g., F*)
# and constructs Table files with the names <Speaker>CoG.txt
# in the Audio subdirectories of the DatabaseFiles/ directory
#
#
###############################################################################
#
# Copyright R.J.J.H. van Son © 2000, 2001
#
# Author Rob van Son
# Institute of Phonetic Sciences & ACLC
# University of Amsterdam
# Herengracht 338
# NL-1016CG Amsterdam, The Netherlands
# Email: Rob.van.Son@hum.uva.nl
#        rob.van.son@workmail.com
# WWW  : http://www.fon.hum.uva.nl/rob/
# mail:  Institute of Phonetic Sciences
#        University of Amsterdam
#        Herengracht 338
#        NL-1016CG Amsterdam
#        The Netherlands
#        tel +31 205252183
#        fax +31 205252197
#
# License for use and disclaimers
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#
#######################################################
#
$HomeDir = '../../..';
require "$HomeDir/Links.pl";
require "$Scripts/CGN_phonemes.pl";  # For the phoneme classes
require "$Scripts/SentenceLabel.pl";

# Use alternate datapaths
if(grep(/\-\-datapath/i, @ARGV))
{
	my $i;
	for($i=0; $i < $#ARGV; ++$i)
	{
		if($ARGV[$i] =~ /\-\-datapath/i)
		{
			$DataPath = $ARGV[$i+1];
			splice(@ARGV, $i, 2);
			
		};
	};
};

my $AlternateTableExtension = "";
if(grep(/\-\-tableextension/i, @ARGV))
{
	my $i;
	for($i=0; $i < $#ARGV; ++$i)
	{
		if($ARGV[$i] =~ /\-\-tableextension/i)
		{
			$AlternateTableExtension = $ARGV[$i+1];
			splice(@ARGV, $i, 2);
			
		};
	};
};

#
# Where are the files
my $TypeExtension = 'Formants';
my $DataDirectory = "$DataPath/$Formants";
if(grep(/\-\-smooth/i, @ARGV))
{
	my $i;
	for($i=0; $i < $#ARGV; ++$i)
	{
		if($ARGV[$i] =~ /\-\-smooth/i)
		{
			$TypeExtension = 'SmoothFormants';
			$DataDirectory = "$DataPath/$SmoothFormants";
			splice(@ARGV, $i, 1);
			
		};
	};
};

my $TableDirectory = "$DatabaseTables/Audio/$TypeExtension";
my $SourceDirectory = "$DatabaseTables/phoneme";


#
# Table to handle
$TablePattern = "PHONEMESphoneme.txt.gz";

@TargetHeaderList = (
'ID [TEXT] ID code of segment', 
'Value [TEXT] Segment label', 
'Valid [CHAR(1)] Boundaries are Valid (hand aligned) or Invalid (unresolved)', 
'Minimum [FLOAT] Minimum value inside segment' ,
'Maximum [FLOAT] Maximum value inside segment', 
'Time0 [FLOAT] Value at start of segment', 
'Time1 [FLOAT] Value 1/4 of segment', 
'Time2 [FLOAT] Value at center of segment', 
'Time3 [FLOAT] Value 3/4 of segment', 
'Time4 [FLOAT] Value at end of segment',
'Tmax [FLOAT] Relative time of Maximum (0-4)',
'Tmin [FLOAT] Relative time of Minimum (0-4)');

# The praat script that reads the values at times 0-4 and 
# minimum and maximum and stores them in valueString$
my $NumberOfValues = 5;

# The Master script that will store ALL praat commands
my @MasterPraatScript = ();

#
# Major loop, process all speakers
my $SpeakerGlob;

foreach $SpeakerGlob (@ARGV)
{
    # Get the label filenames
    @PhonemeTableList = 
    glob("$SourceDirectory/$SpeakerGlob$TablePattern");
    # Process all files
    my $File;
    foreach $File (@PhonemeTableList)
    {	
        my %ColumnHeaders = ();
	
	# Open the file
	open(SOURCETABLE, "gunzip -qc $File|") || die  "gunzip -qc $File|: $!\n";

	# Get the first line
	my $Header = <SOURCETABLE>;
	chomp($Header);
	# Remove leading #
	$Header =~ s/^\s*\#[\>]?\s*//g;

	# Skip comments
	while(($Line = <SOURCETABLE>) =~ /^\s*(\#[\>]?\s*|$)/)
	{ 
	     if($Line =~ /^\s*\#[\>]\s*/)
	     {
		     $Header .= "\t$'";
	   	     chomp($Header);
	     };
	};
	
	my $Counter = 0;
	my @HeaderLine = split(/\t/, $Header);
	$Header = "";
	foreach $Header (@HeaderLine)
	{
	 	my ($HeaderName) = split(' ', $Header);
		$ColumnHeaders{$HeaderName} = $Counter;
		++$Counter;
	};
	
	# Get the positions of the relevant parameters
	my $Speakerpos = $ColumnHeaders{'Speaker'};
	my $ItemIDpos = $ColumnHeaders{'ID'};
	my $Valuepos = $ColumnHeaders{'Value'};
	my $SentenceIDpos = $ColumnHeaders{'SENTENCEID'};
	my $Startpos = $ColumnHeaders{'Start'};
	my $Endpos = $ColumnHeaders{'End'};
	my $StartValidpos = $ColumnHeaders{'StartValid'};
	my $EndValidpos = $ColumnHeaders{'EndValid'};
	my $Durationpos = $ColumnHeaders{'Duration'};
	my $DurationValidpos = $ColumnHeaders{'DurationValid'};
	
	# Process all the lines
	my $FM_exists = 0;
	my $HM_exists = 0;
	my $PreviousSentenceID = "";
	my $SomethingReadIntoPraat = 0;
	while(<SOURCETABLE>)
	{
		next if /^\s*\#/;	# Skip empty lines

		my @Record = split(/\t/, $_);
		 
		my $Speaker = $Record[$Speakerpos];
		my $ItemID = $Record[$ItemIDpos];
		my $Value = $Record[$Valuepos];
		my $SentenceID = $Record[$SentenceIDpos];
		my $Start = $Record[$Startpos];
		my $End = $Record[$Endpos];
		my $StartValid = $Record[$StartValidpos];
		my $EndValid = $Record[$EndValidpos];
		my $Duration = $Record[$Durationpos];
		my $DurationValid = $Record[$DurationValidpos];
		my $TargetFile = "$TableDirectory/$Speaker$AlternateTableExtension$TypeExtension";
		
		# Just in case a record is broken
		next unless $SentenceID =~ /^[FM]\d+[A-Z]+[12]/;
		
		# Read a new file (if necessary)
		if($SentenceID ne $PreviousSentenceID)
		{
		    $FM_exists = shift @{[glob("$DataDirectory/fm/$Speaker/${SentenceID}_fm*.$TypeExtension")]};
		    $HM_exists = shift @{[glob("$DataDirectory/hm/$Speaker/${SentenceID}_hm*.$TypeExtension")]};
		    
		    push(@MasterPraatScript, "select all\n");
		    push(@MasterPraatScript, "Remove\n") if $SomethingReadIntoPraat; 
		    $SomethingReadIntoPraat = 0;
				
			# Only generate errors when the corresponding sound file exists
		    if($FM_exists)
		    {
				push(@MasterPraatScript, "Read from file... $FM_exists\n");
				push(@MasterPraatScript, "Rename... AudioDatafm\n");
				++$SomethingReadIntoPraat;
		    }
		    elsif(glob("$DataPath/sentences/fm/$Speaker/${SentenceID}_fm*"))
		    {
				print STDERR "$ItemID $Value: $DataDirectory/fm/$Speaker/${SentenceID}_fm*.$TypeExtension does not exist\n";
				next;
		    };
		    
		    if($HM_exists)
		    {
				push(@MasterPraatScript, "Read from file... $HM_exists\n");
				push(@MasterPraatScript, "Rename... AudioDatahm\n");
				++$SomethingReadIntoPraat;
		    }
		    elsif(glob("$DataPath/sentences/hm/$Speaker/${SentenceID}_hm*"))
		    {
				print STDERR "$ItemID $Value: $DataDirectory/hm/$Speaker/${SentenceID}_hm*.$TypeExtension does not exist\n";
				next;
		    };
		    
		    $PreviousSentenceID = $SentenceID;
		};
		
		# for each channel separately
		my $Channel;
		foreach $Channel ('fm', 'hm')
		{
		    next if $Channel eq 'fm' && !$FM_exists;
		    next if $Channel eq 'hm' && !$HM_exists;
		    
		    # Construct the script calls
		    for($Formant = 1; $Formant <= 3; ++$Formant)
		    {
				unless(-e "${TargetFile}F${Formant}_$Channel.txt")
				{
					open(TARGETFILE, ">${TargetFile}F${Formant}_$Channel.txt") 
					|| die ">${TargetFile}F${Formant}_$Channel.txt: $!\n";
					print TARGETFILE "#> ", join("\n#> ", @TargetHeaderList), "\n";
					print TARGETFILE "# \n# Formants: F${Formant}\n"; 

					# Print the copyright license
					if(open(LICENSE, "<./licenseterms.txt"))
					{
						my $Date = localtime();
						$Date =~ /\s([\d]+)\s*$/;
						my $Year = $1;
						while(<LICENSE>)
						{
							if(/\©/ && ! /$Year/)
							{
								s/(\d)\s{6}(\s+\#)/\1, $Year\2/ig;
							};
							print TARGETFILE $_;
						};
						close(LICENSE)
					};

					close(TARGETFILE);
				};
			my $ScriptCall = "execute ExtractAndWriteFormants.praat ${TargetFile}F${Formant}_$Channel.txt $ItemID $Value $DurationValid";
			# Delta T for values
			my $DeltaT = $Duration/($NumberOfValues-1);
			# Fill the time points
			my $i;
			for($i = 0; $i < $NumberOfValues; ++$i)
			{
				$ScriptCall .= " ".($Start + $i*$DeltaT);
			};
			$ScriptCall .= " $Formant";

			push(@MasterPraatScript, "select TableOfReal AudioData$Channel\n");

			my $Formant;
			push(@MasterPraatScript, "$ScriptCall $Formant\n");
		    }

		};
	};
	close(SOURCETABLE);
    };
};

# Execute Praat script
if(@MasterPraatScript)
{
	open(PRAAT, "|praat - | sed 's/Praat > //g'") || die "praat: $!\n";
	my $Line;
	foreach $Line (@MasterPraatScript)
	{
		print PRAAT $Line;
		# print STDOUT $Line;
	};
	print PRAAT "Quit\n";
	close(PRAAT);
};
exit;



