/* file mpron4.c */

#if !defined(COMPILE_ENVIRONMENT)
#include <gp/stdcenvf.h> /* std compile environment for functions */
#endif

void make_basic_pron4(struct PRON2 *pron, char *sx,
  struct SYL_PARMS *syl_parms, int *perr)

/**************************************************************/
/* Makes initial pronunciation structure for phone string *sx */
/* in PRON2 *pron, using syllable parameters *syl_parms.      */
/* Modified 1/25/99 to use protected strings internally.      */
/**************************************************************/
 {char *proc = "make_basic_pron4";
  int i,iph,ph_code,iword,nwords,jsylb,nseg,nsylbs;
  int cc_final_style = 2;
  int dbi;
  PROTECTED_INT_STR *xint, *seg_int, *str_int, *bnd_int, *isylb;
  struct INTERVAL1 cluster;
/* coding */
  db_enter_msg(proc,1);

if (db_level > 2) printf("%son entry, sx='%s'\n",pdb,sx);
if (db_level > 2) printf("%siwordbound=%d\n",pdb,syl_parms->iwordbound);

  *perr = 0;
  xint    = create_prot_int_str(12);
  seg_int = create_prot_int_str(12);
  str_int = create_prot_int_str(12);
  bnd_int = create_prot_int_str(12);
  isylb   = create_prot_int_str(5);
  pron->rate_relation = '>';
  pron->rate_value = 0;
  pron->lect[0] = 1;
  pron->lect[1] = 0;
/* do initial encoding into int string xint[] */
  encode3r(sx,syl_parms->pcdp,NULL,xint,perr);
  if (*perr > 0)
    {fprintf(stdout,"*ERR: %s: Encode3r returns perr=%d\n",proc,*perr);
     fprintf(stdout," encoding '%s'\n",sx);
     *perr = 11;
     goto RETURN;
    }

if (db_level > 1)
 {printf("%safter initial encoding, xint->str=",pdb);
  for (dbi=1; dbi <= xint->str[0]; dbi++) printf("%4d",xint->str[dbi]);
  printf("\n");
 }
/* add default stress mark to syllables not marked */
   add_default_stress_prot(xint,syl_parms->pcdp,syl_parms->i_default_stress);

if (db_level > 1)
 {printf("%safter adding default stress, xint->str=",pdb);
  for (dbi=1; dbi <= xint->str[0]; dbi++) printf("%4d",xint->str[dbi]);
  printf("\n");
 }

/* delete initial & final word boundaries, if any */
  if (xint->str[1] == syl_parms->iwordbound)
    {for (i=1; i < xint->str[0]; i++) xint->str[i] = xint->str[i+1];
     xint->str[0] -= 1;
    }
  if (xint->str[xint->str[0]] == syl_parms->iwordbound) xint->str[0] -= 1;

if (db_level > 1)
 {printf("%safter deleting init & final word boundaries, xint->str=",pdb);
  for (dbi=1; dbi <= xint->str[0]; dbi++) printf("%4d",xint->str[dbi]);
  printf("\n");
 }

/* split phones into segments, stresses, and boundaries */
  split_tiers2_prot(seg_int,str_int,bnd_int,xint,syl_parms->pcdp,perr);
  nseg = seg_int->str[0];
/* assign initial syllable structure */
/* initialize with no syllables or associations */
  nsylbs = 0;
  pron->nsylbs =  0;
  isylb->str[0] = 0;
  for (iph=1; iph <= nseg; iph++) nstrcat_prot_i(isylb,0);
/* Rule 1: make a syllable for each syllable nucleus */
  for (iph=1; iph <= nseg; iph++)
    {ph_code = seg_int->str[iph];
     if (strstr(syl_parms->pcdp->pc[ph_code].lc_ext,"syl") != NULL)
       {if (nsylbs < MAX_SYLBS)
          {nsylbs += 1;
           pron->sylb[nsylbs].nucleus = iph;
           pron->sylb[nsylbs].stress = str_int->str[iph];
           pron->sylb[nsylbs].segs.l1 = 0;
           pron->sylb[nsylbs].segs.l2 = 0;
           isylb->str[iph] = nsylbs;
	  }
        else
          {fprintf(stderr,"*ERR:%s: syllable array overflow.\n",proc);
           fprintf(stderr," (Increase MAX_SYLBS and re-compile.)\n");
           *perr = 11; goto RETURN;
    }  }  }
/* assign initial word structure */
  nwords = 1;
  pron->word[nwords].segs.l1 = 1;
  pron->word[nwords].segs.l2 = 1;
  pron->word[nwords].stress = 0;
  for (iph=1; iph <= nseg; iph++)
    {if (bnd_int->str[iph] == syl_parms->iwordbound)
       {if (nwords < MAX_WORDS_IN_UTT)
          {nwords += 1;
           pron->word[nwords].segs.l1 = iph;
           pron->word[nwords].segs.l2 = iph;
	  }
        else
          {fprintf(stderr,"*ERR:%s: word array overflow.\n",proc);
           fprintf(stderr," (Increase MAX_WORDS_IN_UTT and re-compile.)\n");
           *perr = 12; goto RETURN;
       }  }
     else
       {pron->word[nwords].segs.l2 = iph;
    }  }

if (db_level > 1) printf("%safter rule 1, nsylbs=%d\n",pdb,nsylbs);
if (db_level > 1) printf("%snwords=%d\n",pdb,nwords);

/* rule 2: (slow speech) */
/* 2a */
/* for each syllabic nucleus, associate maximal initial cluster */
  for (jsylb=1; jsylb <= nsylbs; jsylb++)
    {cluster.l2 = pron->sylb[jsylb].nucleus - 1;
     cluster.l1 = cluster.l2;
/* NOTE: we must still use word boundary marks instead of which */
/* syllables are in which words because sylb segs haven't been set */
     while (ok_init_cluster2(seg_int->str,cluster,syl_parms) &&
            no_word_boundl(bnd_int->str,cluster,syl_parms->iwordbound)
           ) cluster.l1 -= 1;
     cluster.l1 += 1;
     if (cluster.l1 <= cluster.l2) /* good cluster */
       {pron->sylb[jsylb].segs.l1 = cluster.l1;
        for (iph=cluster.l1; iph <= cluster.l2; iph++)
          isylb->str[iph] = jsylb;
       }
     else
       {pron->sylb[jsylb].segs.l1 = pron->sylb[jsylb].nucleus;
    }  }

if (db_level > 1) printf("%safter rule 2a, nsylbs=%d\n",pdb,nsylbs);

/* 2b */
/* for each syllabic nucleus, associate maximal final non-associated cluster */
  for (jsylb=1; jsylb <= nsylbs; jsylb++)
    {cluster.l1 = pron->sylb[jsylb].nucleus + 1;
   /* NB: must work backward from longest to shortest because of */
   /*    [Vdst#, "amidst"] but *[Vds#]                           */
 
     cluster.l2 = cluster.l1;     /* find maximal cluster */
     while ((cluster.l2 <= nseg) &&
            no_word_boundr(bnd_int->str,cluster,syl_parms->iwordbound)&&
            (isylb->str[cluster.l2] == 0 )) cluster.l2 += 1;
     cluster.l2 -= 1;
  /* style # 1 - stop here */
  /* style # 2 - back off to o.k. final cluster */
     if (cc_final_style == 2)
       {while ((cluster.l2 >= cluster.l1)&&
               (!ok_final_cluster2(seg_int->str,cluster,syl_parms)))
          cluster.l2 -= 1;
       }
     if (cluster.l1 <= cluster.l2) /* good cluster */
       {pron->sylb[jsylb].segs.l2 = cluster.l2;
        for (iph=cluster.l1; iph <= cluster.l2; iph++)
          isylb->str[iph] = jsylb;
       }
     else
       {pron->sylb[jsylb].segs.l2 = pron->sylb[jsylb].nucleus;
    }  }

if (db_level > 1) printf("%safter rule 2b, nsylbs=%d\n",pdb,nsylbs);

/* mark syllables as to what word they (initially) belong to */
  for (iword=1; iword <= nwords; iword++)
    {for (jsylb = 1; jsylb <= nsylbs; jsylb += 1)
       {if ((pron->sylb[jsylb].segs.l1 >= pron->word[iword].segs.l1)&&
            (pron->sylb[jsylb].segs.l2 <= pron->word[iword].segs.l2) )
          pron->sylb[jsylb].iword = iword;
    }  }

 RETURN:
  pron->nsylbs = nsylbs;
  pron->nwords = nwords;
  nstrcpy(pron->seg,seg_int->str);
  destroy_prot_int_str(xint);
  destroy_prot_int_str(seg_int);
  destroy_prot_int_str(str_int);
  destroy_prot_int_str(bnd_int);
  destroy_prot_int_str(isylb);

if (db_level > 1) dump_pron2(pron);

  db_leave_msg(proc,1);
  return;
 } /* end make_basic_pron4() */
