#! /bin/ksh

# applique un fichier de f0 en ascii sur un fichier format "phoneme duree" 
# Le fichier est une serie temporelle, par defaut une valeur toutes les
# 10 ms
# format: une valeur en Hz par ligne
#
# codage fichier phoneme :sampa ou dutoit selon option specifiee


commande=${0##*/}

#codes dutoit
commentaire='^;'
code_pause='_'


##########
usage()
{
   {
     print -- "usage: $commande  -pho fichier [-f0 fichier] [-pas_f0
aleur_ms] > "
     print -- "usage: $commande  -sampa fichier [-f0 fichier] [-pas_f0
aleur_ms] > "
     print -- "-pho fichier "
     print -- "      nom d'un fichier \".pho\" ( phoneme code mbrola v1.02), ou
 pour entree standard"
     print -- "-sampa fichier "
     print -- "      nom d'un fichier  \".pho\" ( phoneme code sampa) , ou
 pour entree standard"
     print -- " Ces deux options sont mutuellement exclusives"
     print -- ""

     print -- "-f0  fichier "
     print -- "     nom d'un fichier de f0, ou - pour entree standard (par
defaut)"
     print -- "     une valeur de Hz (ascii) par ligne et par trame"

     print -- "-pas_f0  valeur_ms" 
     print -- "     valeur du pas de trame du fichier de f0 (defaut: 10ms)"
   
   } >/dev/stderr 
}


##########
use()
{
   {
     print -- "usage: $commande  -pho file [-f0 file] [-pas_f0 value_ms] > "
     print -- "usage: $commande  -sampa file [-f0 file] [-pas_f0 value_ms] > "

     print -- "-pho file "
     print -- "      name of a \".pho\" file (mbrola v1.02 code) , or - for
tandard input"

     print -- "-sampa file "
     print -- "     name of a \".pho\" file  (sampa code) , or - for
tandard input"
     
     print -- " These two options are exclusive mutually "
     print -- ""

     print -- "-f0  file "
     print -- "     name of an f0 file , or - for standard input (default)"
     print -- "     one  Hz  value (ascii) per line and per frame"

     print -- "-pas_f0  value_ms" 
     print -- "     frame interval (in ms) of the f0 file (default: 10)"
   
   } >/dev/stderr 
}

##########
erreur()
{
   print "$commande: $@"  >/dev/stderr
}


###############  maitre #############

# Taux de desechantillonnage du fichier de f0 et frame interval
# these two parameters are related to obtain a "not too big" number
# of f0 targets points in the ".pho" file
# 20 ms (delta_f0 *pas_f0 ) seems to be a good compromise

delta_f0=2
pas_f0=10

fic_f0='-'
fic_pho=''
sampa_en_pho=0 

# zzz pour etre sur d'etre derriere tout phoneme
bali_f0="zzzF0_F0_"

# analyse arguments

while test "X$1" != "X"
do
case $1 in
-f0) fic_f0=$2; shift 2 ;;
-pho*) fic_pho=$2; sampa_en_pho=0 ;shift 2 ;;
-sampa*) fic_pho=$2;  sampa_en_pho=1 ;shift 2 ;;

-pas_f0 ) pas_f0=$2 ; shift 2;;
-usage|-aide|-sos) usage ; exit 0 ;;
-use|-help) use ; exit 0 ;;
*) usage ; exit 1;;
esac
done

 
if test "X${fic_f0}${fic_pho}" = "X--" 
then
   erreur "fichiers f0 et pho ne peuvent etre simultanement sur l'entree
tandard"
   exit 1
fi

case "$fic_f0" in
-) muet=0
  ;;

*) if test ! -f "$fic_f0"  -a ! -p "$fic_f0" 
   then
   erreur "ne peut ouvrir fichier f0 $fic_f0"
   exit 1
   fi
   ;;
esac

if test -z "$fic_pho" -o \( "$fic_pho" != '-' -a ! -f "$fic_pho" -a ! -p
$fic_pho" \)
then
   erreur "fichier de phonemes $fic_pho inaccessible ou absent"
   exit 1
fi

# bloc balisage et concatenation des fichier f0 et fichier phoneme
{
# To deal with a non-ascii f0 file, just change the next line with something
# like that : CONV_2_ASCII $fic_f0 |nawk ' ....

  cat $fic_f0  |nawk '
  BEGIN {
			delta_f0='$delta_f0'
  			bali_f0="'$bali_f0'"
  			pas_f0='$pas_f0'
  			
  			code_pause="'$code_pause'"
  			}
  			
  	(NR-1) % delta_f0 == 0	{
  				print bali_f0 , (NR-1)*pas_f0, int($1 +0.5)
  			}
  	END {
  			print code_pause , NR*pas_f0
  		}
  		'
  
  # genere un fichier en tps cumule pour interclassement
  # conversion sampa -> dutoit si specifie
  # filtre les lignes vides et commentaires
   {
   	case $sampa_en_pho in
   		1) prosampa $fic_pho ;;
   		*) cat $fic_pho  ;;
   	esac
   } |nawk '
  	BEGIN {
  		tcum = 0
  		commentaire="'$commentaire'"
  	}
  	
  	NF == 0 { next }
	$1 ~ commentaire { next }
	 
	NF < 2 {
				print "ligne",NR, ":", $0  >  "/dev/stderr"
				print "est incorrecte, elle est ignoree" 	>  "/dev/stderr"
				next
			}

  	{   		
  		 print $1, tcum 
  		 tcum += $2 
  	}

  	'
#  on sort le tout sur un tri temporel sur deuxieme champ  
} |sort -bn  +1 -2   |\
nawk ' 
BEGIN {
   bali_f0="'$bali_f0'"
   lim_vnv=25
   nb_max_cible=20
   t_phon_g=-1
   n=0
   liste=""
}

####declaration fonction valeur absolue
function abs(val) {

if (val <0 )
   return (-val)
else
   return(val)
}
##########

$1 == bali_f0 {
				t_abs_f0[n] = $2
				hz[n] = $3
				n++
				next
				}
				
NR == 1 {
			phon_g=$1
			t_phon_g = $2
			next
			}
			
# phoneme
{
	duree_phon = $2 - t_phon_g
	if (duree_phon >0)
	{

# tri des cibles f0 car probleme de nbre max de cibles pour mbrola
# ote cibles inutiles 
# garde au moins 2 cibles si au moins 2 cibles presentes
# sur phoneme pause, ne garde que la 1ere et derniere cible

   if (n >0 )
   {
   	# 1ere cible
   	t_courant = t_abs_f0[0]
   	hz_courant = hz[0]
   	ncible_diff = 1
	   t_rel = t_courant - t_phon_g
		t_pourcent = int(100 * t_rel/duree_phon  +0.5)
		liste_f0 = liste_f0 " " t_pourcent " " hz_courant
   	
      if ( phon_g != "_" )
      {
      
			for(i=1; i <n; i++)
			{
		   	if (hz_courant < lim_vnv && hz[i] < lim_vnv )
		      	continue
		   	if ( abs(hz_courant - hz[i]) < 1 )
		   		continue
		   	
   			t_courant = t_abs_f0[i]
   			hz_courant = hz[i]
   			ncible_diff++
		   	
				t_rel = t_courant - t_phon_g
				t_pourcent = int(100 * t_rel/duree_phon  +0.5)
				liste_f0 = liste_f0 " " t_pourcent " " hz_courant
			}
		
		}

	# il faut au moins 2 cibles si il y avait plus de une cible initialement
	# ds ce cas on garde alors la derniere de la liste brute 
      if (n > 1 && ncible_diff == 1)
      {
          t_rel = t_abs_f0[n-1]  -t_phon_g         
			 t_pourcent = int(100 * t_rel/duree_phon  +0.5)
			 liste_f0 = liste_f0 " " t_pourcent " " hz[n-1]
			 ncible_diff ++
		}
 
	   if (ncible_diff > nb_max_cible)
	   {
	   	print "ligne",phon_g,duree_phon    > "/dev/stderr"
	   	print "trop de cibles f0 (",ncible_diff, "),  " ,nb_max_cible,"au plus"  > "/dev/stderr"
		}
		print phon_g , duree_phon, liste_f0
		liste_f0 = ""
		n = 0
	} #  n>0

	} #  duree_phon >0
	
	phon_g=$1
	t_phon_g=$2
}
