#! /usr/bin/perl -w
use strict;
my $VERBOSE = 0;
my $DEBUG = 0;

# (c) 2007, Sébastien Blondeel.
# Assists the transcription using timecodes pre-computed by another application.

my $MEDIA_FILE = $ENV{"MEDIA_FILE"};
if ($MEDIA_FILE =~ m{\.ogg$}s) {
  my $wav_file = $MEDIA_FILE;
  $wav_file =~ s{\.ogg$}{.wav}s;
  $MEDIA_FILE = $wav_file if -e $wav_file;
}
die "Usage: $0 <media_file>\n" unless defined $MEDIA_FILE;

{ # VIM configuration
my $tmp = << 'EOTMP';
" Start the chunk
:map <F1> :.,$!perl P.pl<CR>
" Tag afterwards: type this on the first line of the rest of the transcription
:map <F2> Gdd''P<F1>
:syntax match TimeCode /^\[\[[0-9].*$/
:highlight TimeCode ctermfg=DarkGreen
EOTMP
}

# Use "" to have no beeps
my $beep = "/usr/bin/play /usr/share/sounds/KDE_Beep_Pop.wav; ";
$beep = "";

my $SHOW_STAT = 0;
my $OVERLAP = .01;

my $sav = $/;
undef $/;
my $ARG = <>;
$/ = $sav;

# print STDERR "RECEIVED:\n$ARG\nEND_RECEIVED\n";

my $START = 0;

if ($ARG =~ s{^([^\n]+)\n\s*}{}s) {
  $START = $1;
  $START =~ s{\s+sil=\d+(?:\.\d*)?\s*$}{}s;
  $START =~ s{\s+syl=\d+\s*$}{}s;
}

$ARG =~ s{\s*\[\[\s*([\d\.:]+)\s*\]\]\s*$}{}s;
$ARG =~ s{\s*$}{\n}s;
$ARG =~ s{^\s*$}{}s;

$START =~ s{^\s*\[\[\s*([\d\.:]+)\s*\]\]\s*$}{$1}s;
if ($START =~ m{^(\d+):(\d+):(\d+(?:\.\d*)?)$}s) {
  $START = (3600 * $1) + (60 * $2) + $3;
} elsif ($START =~ m{^(\d+):(\d+(?:\.\d*)?)$}s) {
  $START = (60 * $1) + $2;
} elsif ($START =~ m{^(\d+(?:\.\d*)?)$}s) {
  $START = $1;
} else {
  die "$0: FATAL: Could not parse first line: \"$START\".\n$START\n$ARG\n";
}

sub pretty {
  my ($sec, $syl, $sil) = @_;
  $syl = 0 unless defined $syl; # Number of syllables
  $sil = 0 unless defined $sil; # Length of silence

  my ($hh, $mm, $ss, $time) = (0, 0, 0, "");

  if ($sec > 3600) {
    $hh = sprintf("%d", $sec / 3600);
    $sec -= 3600 * $hh;
    $time .= "$hh:";
  }

  if ($hh || ($sec > 60)) {
    $mm = sprintf("%02d", $sec / 60);
    $sec -= 60 * $mm;
    $time .= "$mm:";
  }

  $ss = int($sec);
  $sec -= $ss;
  
  $time .= sprintf("%02d", $ss);

  my $str = sprintf("%.02f", $sec);
  $str =~ s{^0\.}{.}s;
  $time .= $str;

  $time = "[[$time]]";

  if ($syl) {
    $time .= " syl=$syl";
  }

  if ($sil) {
    $time .= " sil=".sprintf("%.2f", $sil);
  }
 
  return $time;
}

#######################################

my $sum_syl = 0;
my $sum_sil = 0;
my $sum_len = 0;

my @H = ();;
my $N;
while (<DATA>) {
  if (m/^\s*
      (\d+\.\d+)\s+
      (\d+\.\d+)\s+
      (\d+\.\d+)\s+
      (\d+\.\d+)\s+
      (\d+)\s*$/sx) {
    my ($start, $end, $len, $sil, $syl) = ($1, $2, $3, $4, $5);
    push @H, [
      $start,
      $end,
      $len,
      $sil,
      $syl,
    ];
    $sum_syl += $syl;
    $sum_sil += $sil;
    $sum_len += $len;
    # TODO sanity checks: len, start / end...
  } else {
    die "$0: Cannot parse date line:\n$_\n";
  }
}
$N = scalar @H;

if ($SHOW_STAT) {
  print STDERR "$N chunks\n";
  print STDERR "Mean syllables in chunk: ".sprintf("%.2f", $sum_syl/$N)."\n";
  print STDERR "Mean silence cut: ".sprintf("%.2f", $sum_sil/$N)." sec.\n";
  print STDERR "Mean chunk length: ".sprintf("%.2f", $sum_len/$N)." sec.\n";
  exit;
}

my $i = 0;
my ($start0, $end0, $len0, $sil0, $syl0);
for (my $i = 0; $i < $N; $i++) {
  my ($start, $end, $len, $sil, $syl) = @{$H[$i]};
  if ($start <= $START && $end > $START) {
    my $sil0 = 0;
    if ($i>0) {
      ($start0, $end0, $len0, $sil0, $syl0) = @{$H[$i-1]};
    }
print STDERR "LEN 01 = $len (start=$start)\n" if $VERBOSE;
    # print STDERR "DEBUG: START=$START start=$start end=$end len=$len sil=$sil syl=$syl\n";
    my $st = &pretty($start, $syl, $sil);
    $ARG = $ARG."\n" if $sil0 > 1.5; # Previous long silence in the end: new paragraph
    my $en = &pretty($end+0.01);
    print("$st\n$ARG$en");
    # $start -= $sil0; 
    # $len   += $sil0; 
print STDERR "LEN 02 = $len (start=$start) (sil0=$sil0)\n" if $VERBOSE;

    my $bef = ""; # Before
    my $aft = ""; # After

    # Overlap if no beep.
    unless ($beep =~ m{\S}s) { # No beep
      if ($start > $OVERLAP) {
        $start -= $OVERLAP; 
        $len   += $OVERLAP; 
print STDERR "LEN 03 = $len (start=$start)\n" if $VERBOSE;
      } else {
        $len += $start;
print STDERR "LEN 04 = $len (start=$start)\n" if $VERBOSE;
        $start = 0;
      }
      $len += $OVERLAP;
print STDERR "LEN 05 = $len (start=$start)\n" if $VERBOSE;
    } else { # Beep
      if ($start > $OVERLAP) {
        my $before = $start - $OVERLAP;
        $bef = 
        "/usr/bin/play $MEDIA_FILE trim $before $OVERLAP; ". # Stop at the end of the silence
        "$beep";
print STDERR "BEF = /usr/bin/play $MEDIA_FILE trim $before $OVERLAP; [BEEP]\n" if $VERBOSE; # Stop at the end of the silence
      }
      $aft = $beep."/usr/bin/play $MEDIA_FILE trim $end $OVERLAP; ";
print STDERR "AFT = [BEEP] /usr/bin/play $MEDIA_FILE trim $end $OVERLAP; " if $VERBOSE;
    }
    
print STDERR "LEN 06 = $len (start=$start)\n" if $VERBOSE;
    print STDERR "\n".
      "$bef\n".
      "/usr/bin/play $MEDIA_FILE trim $start $len;\n".
      "$aft\n" if $VERBOSE;

    print STDERR
      "/usr/bin/play $MEDIA_FILE trim $start $len; # OVERLAP=$OVERLAP\n" if 0; # Stop at the end of the silence

    if ($0 =~ m{PP\.pl}s) { # more overlap in the beginning
      $start -= 1.0;
      $len   += 1.0;
    }

    my $COMMAND = "".
      "killall play > /dev/null 2> /dev/null; ".
      "($bef".
      "/usr/bin/play $MEDIA_FILE trim $start $len; ". # Stop at the end of the silence
      "$aft".
      ") > /dev/null 2> /dev/null &";
    print STDERR "$COMMAND\n" if $DEBUG;
    system($COMMAND);
    exit;
  }
}

__DATA__
