#! /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 general Audio values values.
#
# Use:
# ./ConstructAudioTables.pl <AudioAnalysisType> [SpeakerGlob]
#
# --datapath <DataPath> (e.g., ~/NewSLspeech) for an alternative 
#   source of formant files (NOTE: uses <DataPath>/CenterOfGravity as the
#   actual path)
#
# --tableextension <name> (e.g., 'New') Name added to the table
#   names to distinguish them from the "standard" ones.
#
# 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);
			
		};
	};
};

#
# A list of type extension/object name pairs
my %TypeBase =
(
'Pitch' => 'PitchTier',
'SmoothPitch' => 'PitchTier',
'Intensity' => 'Intensity',
'cog' => 'Sound'
);
#
# Where are the files
my $TypeExtension = shift(@ARGV);
my $TypeName = exists($TypeBase{$TypeExtension}) ? $TypeBase{$TypeExtension} : $TypeExtension;

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

my $DataDirectory = "$DataPath/$TypeExtension";

#
# 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)',
'mean [FLOAT] Mean value',
'sd [FLOAT] Standard Deviation'
);
# No means for Formants
(pop(@TargetHeaderList) && pop(@TargetHeaderList)) if $TypeExtension =~ 'Formants' ;

# 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;
@ARGV = glob("$DataDirectory/fm/*") unless @ARGV;
foreach $SpeakerGlob (@ARGV)
{
    $SpeakerGlob =~ m@/?([^/]+)$@;
    $SpeakerGlob = $1;
    # 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
		
		# 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;
			
		    if($FM_exists)
		    {
				push(@MasterPraatScript, "Read from file... $FM_exists\n");
				push(@MasterPraatScript, "Rename... AudioDatafm\n");
				++$SomethingReadIntoPraat;
print STDERR "FM $FM_exists\n";
		    }
		    elsif(glob("$DataPath/sentences/fm/$Speaker/${SentenceID}_fm*"))
		    {
				print STDERR "$ItemID $Value: FM $FM_exists does not exist as $DataDirectory/fm/$Speaker/${SentenceID}_fm*.$TypeExtension\n";
				next;
		    };
		    
		    if($HM_exists)
		    {
				push(@MasterPraatScript, "Read from file... $HM_exists\n");
				push(@MasterPraatScript, "Rename... AudioDatahm\n");
				++$SomethingReadIntoPraat;
print STDERR "HM $HM_exists\n";
		    }
		    elsif(glob("$DataPath/sentences/hm/$Speaker/${SentenceID}_hm*"))
		    {
				print STDERR "$ItemID $Value: HM $HM_exists does not exist as $DataDirectory/hm/$Speaker/${SentenceID}_hm*.$TypeExtension\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;
		    
		    unless(-e "${TargetFile}_$Channel.txt")
		    {
			    open(TARGETFILE, ">${TargetFile}_$Channel.txt") 
			    || die ">${TargetFile}_$Channel.txt: $!\n";
			    print TARGETFILE "#> ", join("\n#> ", @TargetHeaderList), "\n";
			    print TARGETFILE "# \n# $TypeExtension\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);
		    };
	
		    # Construct the script call
		    my $ScriptCall = "execute ExtractAndWriteValues.praat ${TargetFile}_$Channel.txt $ItemID $Value $DurationValid";
		    $ScriptCall = "execute ExtractAndWritePitchValues.praat ${TargetFile}_$Channel.txt $ItemID $Value $DurationValid"
		    if $TypeExtension eq 'Pitch' || $TypeExtension eq 'SmoothPitch' ;
		    # 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);
		    };

		    push(@MasterPraatScript, "select $TypeName AudioData$Channel\n");
		    push(@MasterPraatScript, "$ScriptCall\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 PRAAT "Quit\n";
	close(PRAAT);
};
exit;



