#!/usr/bin/perl
###############################################
# process a long sound file and a corresponding praat textgrid by the Czech aligner/labeller
# written by Pavel Vondricka <Pavel.Vondricka@ff.cuni.cz> for Sound2Sense project
#
###############################################
# usage: align_soundfile.pl <soundfile.wav> <n>
# - where <soundfile.wav> is the recording and <n> is the number of tier 
# (i.e. the speakers tier) to process for speech
# - the script expects to find a corresponding TextGrid <soundfile.TextGrid>
# in the same directory as the <soundfile.wav>
# - the result is a new textgrid called <soundfile.tier<n>.TextGrid> created 
# in the current directory which includes 5 tiers: RefPhones, AutoPhones (at the moment identical),
# Words and Phrases as produced by the aligner, and the original transcription in the 5th tier

use utf8;
use open ':encoding(utf8)';
binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");

#### SET PATHS HERE ####
# path to the labtool directory
$maindir = "${ENV{'HOME'}}/labtool" ;
#path to the aligner/script
$aligner = "$maindir/align_phrase_general.pl";
########################

$tempdir = $maindir."/temp";
$snd = $tempdir."/chunk";
$sox = "sox";

$filename = $ARGV[0];
$tier = $ARGV[1];
$textgrid = $filename;
$textgrid =~ s/.wav$/.TextGrid/;

@intervals = ();

# Read intervals from the chosen tier
open TEXTGRID, $textgrid;
while (<TEXTGRID>) { 
	if (/xmin = ([0-9\.]+)/) { $xmin = $1; }
	if (/xmax = ([0-9\.]+)/) { $xmax = $1; }
	last if /item \[/;
}
while (<TEXTGRID>) { last if /item \[$tier\]:/;  }
$from = 0; $to = 0;
while (<TEXTGRID>) { 
	last if /item \[/;
	if (/xmin = ([0-9\.]+)/) { $from = $1; }
	if (/xmax = ([0-9\.]+)/) { $to = $1; }
	if (/text = "\s*(.*)\s*"\s*$/) { 
		push @intervals, "$from\t$to\t$1"; 
		$from = 0; $to = 0;
	}
}
close TEXTGRID;
$intervalcnt = scalar @intervals;

# parse each interval
$i=0;
foreach (@intervals) {
	$i++;
	($from,$to,$text) = split "\t";
	# skip intervals not containing any speech but just noise
	$test = $text; $test =~ s/\[[^\]]*\]//g;
	if ($test =~ /^\s*$/) {
		printf "Skipping   [$i/$intervalcnt]... %.4f-%.4f: ".$text."\n",$from,$to;
		next;
	}
	# Process a speech chunk
	printf "Processing [$i/$intervalcnt]... %.4f-%.4f: ".$text."\n",$from,$to;
	$length = $to - $from;
	$command = "$sox $filename $snd.wav trim $from $length" ;
        system $command ;
	# replace [breath] with a silent pause
	$text =~ s/\[breath[^\]]*\]/[sil]/g;
	# replace pauses filled with strange sounds with [fil]
	$text =~ s/\[voc\]/[fil]/g;
	$text =~ s/\[per\]/[fil]/g;
	# replaced filled pauses with [fil]
	$text =~ s/\[hm\]/[fil]/g;
	# try to replace schwa-filled-pauses with a "phonetic transcription"
	$text =~ s/\[ee\]/\@/g;
	$text =~ s/\[ehe\]/\@h\@/g;
	# replace orthographical form with real pronunciation when given explicitly
	$text =~ s/[^\s]*\[pron=([^\]]*)\]/$1/g;
	# strip all tags
	$text =~ s/\\[xvdfop\-]//g;
	# separate words bound by a dash
	$text =~ s/-/ /g;
	&create_empty_textgrid;
	$command = "$aligner -wlen 16 -nonrm 1 $snd.wav >$maindir/align_phrase.log 2>&1";
	#print "$command\n" ;
	system $command;
	#last if $to>30; # just for testing...
}

# Read RefPhones
@phones = ();
open PHONES, '<:encoding(iso-8859-2)', "$snd.TextGrid2.part2";
$lasttime = $xmin;
while (<PHONES>) { 
	last if /item \[/;
	if (/xmin = ([0-9\.]+)/) { $from = $1; }
	if (/xmax = ([0-9\.]+)/) { $to = $1; }
	if (/text = "\s*(.*)\s*"\s*$/) {
		if ($from>$lasttime) 
			{ push @phones, "$lasttime\t$from\t"; }
		push @phones, "$from\t$to\t$1";
		$lasttime = $to;
		$from = 0; $to = 0;
	}
}
close PHONES;
if ($lasttime<$xmax) { push @phones, "$lasttime\t$xmax\t"; }
$phonecnt = scalar @phones;

# Read words
@words = ();
open WORDS, '<:encoding(iso-8859-2)', "$snd.TextGrid2.part3";
$lasttime = $xmin;
while (<WORDS>) { 
	last if /item \[/;
	if (/xmin = ([0-9\.]+)/) { $from = $1; }
	if (/xmax = ([0-9\.]+)/) { $to = $1; }
	if (/text = "\s*(.*)\s*"\s*$/) {
		if ($from>$lasttime) 
			{ push @words, "$lasttime\t$from\t"; }
		push @words, "$from\t$to\t$1";
		$lasttime = $to; 
		$from = 0; $to = 0;
	}
}
close WORDS;
if ($lasttime<$xmax) { push @words, "$lasttime\t$xmax\t"; }
$wordcnt = scalar @words;

# Read phrases
@phrases = ();
open WORDS, '<:encoding(iso-8859-2)', "$snd.TextGrid2.part4";
$lasttime = $xmin;
while (<WORDS>) { 
	last if /item \[/;
	if (/xmin = ([0-9\.]+)/) { $from = $1; }
	if (/xmax = ([0-9\.]+)/) { $to = $1; }
	if (/text = "\s*(.*)\s*"\s*$/) {
		if ($from>$lasttime) 
			{ push @phrases, "$lasttime\t$from\t"; }
		push @phrases, "$from\t$to\t$1";
		$lasttime = $to; 
		$from = 0; $to = 0;
	}
}
close WORDS;
if ($lasttime<$xmax) { push @phrases, "$lasttime\t$xmax\t"; }
$phrasecnt = scalar @phrases;

# Create new TextGrid
$filename =~ s/.wav$//;
open NEWGRID, ">$filename.tier$tier.TextGrid";

print NEWGRID "File type = \"ooTextFile\"
Object class = \"TextGrid\"

xmin = $xmin
xmax = $xmax
tiers? <exists>
size = 5
item []:
    item [1]:
        class = \"IntervalTier\"
        name = \"RefPhones\"
        xmin = $xmin
        xmax = $xmax
        intervals: size = $phonecnt
";
$i=1;
foreach $phone (@phones) {
	($from,$to,$text) = split "\t", $phone;
	print NEWGRID "        intervals [$i]:
            xmin = $from
            xmax = $to
            text = \"$text\"\n";
	$i++;
}
print NEWGRID "    item [2]:
        class = \"IntervalTier\"
        name = \"AutoPhones\"
        xmin = $xmin
        xmax = $xmax
        intervals: size = $phonecnt
";
$i=1;
foreach $phone (@phones) {
	($from,$to,$text) = split "\t", $phone;
	print NEWGRID "        intervals [$i]:
            xmin = $from
            xmax = $to
            text = \"$text\"\n";
	$i++;
}
print NEWGRID "    item [3]:
        class = \"IntervalTier\"
        name = \"Words\"
        xmin = $xmin
        xmax = $xmax
        intervals: size = $wordcnt
";
$i=1;
foreach $word (@words) {
	($from,$to,$text) = split "\t", $word;
	print NEWGRID "        intervals [$i]:
            xmin = $from
            xmax = $to
            text = \"$text\"\n";
	$i++;
}
print NEWGRID "    item [4]:
        class = \"IntervalTier\"
        name = \"Phrases\"
        xmin = $xmin
        xmax = $xmax
        intervals: size = $phrasecnt
";
$i=1;
foreach $phrase (@phrases) {
	($from,$to,$text) = split "\t", $phrase;
	print NEWGRID "        intervals [$i]:
            xmin = $from
            xmax = $to
            text = \"$text\"\n";
	$i++;
}
print NEWGRID "    item [5]:
        class = \"IntervalTier\"
        name = \"Transcription\"
        xmin = $xmin
        xmax = $xmax
        intervals: size = $intervalcnt
";
$i=1;
foreach $phrase (@intervals) {
	($from,$to,$text) = split "\t", $phrase;
	print NEWGRID "        intervals [$i]:
            xmin = $from
            xmax = $to
            text = \"$text\"\n";
	$i++;
}
close NEWGRID;

# Delete temporary files
system "rm $snd*";

### CREATE an empty textgrid for the aligner
sub create_empty_textgrid {


$template = 'File type = "ooTextFile"
Object class = "TextGrid"

xmin = {xmin}
xmax = {xmax} 
tiers? <exists> 
size = 4 
item []: 
    item [1]:
        class = "IntervalTier" 
        name = "RefPhones" 
        xmin = {xmin} 
        xmax = {xmax} 
        intervals: size = 1 
        intervals [1]:
            xmin = {xmin} 
            xmax = {xmax} 
            text = "" 
    item [2]:
        class = "IntervalTier" 
        name = "AutoPhones" 
        xmin = {xmin} 
        xmax = {xmax} 
        intervals: size = 1 
        intervals [1]:
            xmin = {xmin} 
            xmax = {xmax} 
            text = "" 
    item [3]:
        class = "IntervalTier" 
        name = "Words" 
        xmin = {xmin} 
        xmax = {xmax} 
        intervals: size = 1 
        intervals [1]:
            xmin = {xmin} 
            xmax = {xmax} 
            text = "" 
    item [4]:
        class = "IntervalTier" 
        name = "Phrase" 
        xmin = {xmin} 
        xmax = {xmax} 
        intervals: size = 1 
        intervals [1]:
            xmin = {xmin} 
            xmax = {xmax} 
            text = "{text}"
';
$template =~ s/{xmin}/$from/g;
$template =~ s/{xmax}/$to/g;
$template =~ s/{text}/$text/g;

open TEMPGRID, ">$snd.TextGrid";
print TEMPGRID $template;
close TEMPGRID;
}