/* hts_engine for the RHVoice speech synthesis system, a modified version */
/* of the original hts_engine, implementing streaming synthesis and other */
/* features RHVoice needs. */

/* Copyright (C) 2016-2022  Olga Yakovleva <olga@rhvoice.org> */

/* 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, see <https://www.gnu.org/licenses/>. */

/* ----------------------------------------------------------------- */
/*           The HMM-Based Speech Synthesis Engine "hts_engine API"  */
/*           developed by HTS Working Group                          */
/*           http://hts-engine.sourceforge.net/                      */
/* ----------------------------------------------------------------- */
/*                                                                   */
/*  Copyright (c) 2001-2015  Nagoya Institute of Technology          */
/*                           Department of Computer Science          */
/*                                                                   */
/*                2001-2008  Tokyo Institute of Technology           */
/*                           Interdisciplinary Graduate School of    */
/*                           Science and Engineering                 */
/*                                                                   */
/* All rights reserved.                                              */
/*                                                                   */
/* Redistribution and use in source and binary forms, with or        */
/* without modification, are permitted provided that the following   */
/* conditions are met:                                               */
/*                                                                   */
/* - Redistributions of source code must retain the above copyright  */
/*   notice, this list of conditions and the following disclaimer.   */
/* - Redistributions in binary form must reproduce the above         */
/*   copyright notice, this list of conditions and the following     */
/*   disclaimer in the documentation and/or other materials provided */
/*   with the distribution.                                          */
/* - Neither the name of the HTS working group nor the names of its  */
/*   contributors may be used to endorse or promote products derived */
/*   from this software without specific prior written permission.   */
/*                                                                   */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND            */
/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,       */
/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF          */
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */
/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   */
/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY    */
/* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/* POSSIBILITY OF SUCH DAMAGE.                                       */
/* ----------------------------------------------------------------- */

#ifndef HTS_LABEL_C
#define HTS_LABEL_C

#ifdef __cplusplus
#define HTS_LABEL_C_START extern "C" {
#define HTS_LABEL_C_END   }
#else
#define HTS_LABEL_C_START
#define HTS_LABEL_C_END
#endif                          /* __CPLUSPLUS */

HTS_LABEL_C_START;

#include <stdlib.h>             /* for atof() */
#include <ctype.h>              /* for isgraph(),isdigit() */

/* hts_engine libraries */
#include "HTS_hidden.h"

static HTS_Boolean isdigit_string(char *str)
{
   int i;

   if (sscanf(str, "%d", &i) == 1)
      return TRUE;
   else
      return FALSE;
}

/* HTS_Label_initialize: initialize label */
void HTS_Label_initialize(HTS_Label * label)
{
   label->head = NULL;
   label->size = 0;
   label->view_pos_in_utt = 0;
}

/* HTS_Label_check_time: check label */
static void HTS_Label_check_time(HTS_Label * label)
{
   HTS_LabelString *lstring = label->head;
   HTS_LabelString *next = NULL;

   if (lstring)
      lstring->start = 0.0;
   while (lstring) {
      next = lstring->next;
      if (!next)
         break;
      if (lstring->end < 0.0 && next->start >= 0.0)
         lstring->end = next->start;
      else if (lstring->end >= 0.0 && next->start < 0.0)
         next->start = lstring->end;
      if (lstring->start < 0.0)
         lstring->start = -1.0;
      if (lstring->end < 0.0)
         lstring->end = -1.0;
      lstring = next;
   }
}

/* HTS_Label_load: load label */
static void HTS_Label_load(HTS_Label * label, size_t sampling_rate, size_t fperiod, HTS_File * fp)
{
   char buff[HTS_MAXBUFLEN];
   HTS_LabelString *lstring = NULL;
   double start, end;
   const double rate = (double) sampling_rate / ((double) fperiod * 1e+7);

   if (label->head || label->size != 0) {
      HTS_error(1, "HTS_Label_load_from_fp: label is not initialized.\n");
      return;
   }

   /* parse label file */
   while (HTS_get_token_from_fp(fp, buff)) {
      if (!isgraph((int) buff[0]))
         break;
      label->size++;

      if (lstring) {
         lstring->next = (HTS_LabelString *) HTS_calloc(1, sizeof(HTS_LabelString));
         lstring = lstring->next;
      } else {                  /* first time */
         lstring = (HTS_LabelString *) HTS_calloc(1, sizeof(HTS_LabelString));
         label->head = lstring;
      }
      RHVoice_parsed_label_string_init(&(lstring->parsed));
      if (isdigit_string(buff)) {       /* has frame infomation */
         start = atof(buff);
         HTS_get_token_from_fp(fp, buff);
         end = atof(buff);
         HTS_get_token_from_fp(fp, buff);
         lstring->start = rate * start;
         lstring->end = rate * end;
      } else {
         lstring->start = -1.0;
         lstring->end = -1.0;
      }
      lstring->next = NULL;
      lstring->name = HTS_strdup(buff);
      lstring->dur_mod=1.0;
      if(!RHVoice_parse_label_string(lstring->name,&(lstring->parsed)))
        HTS_error(1,"Cannot parse label string\n");
   }
   HTS_Label_check_time(label);
}

/* HTS_Label_load_from_fn: load label from file name */
void HTS_Label_load_from_fn(HTS_Label * label, size_t sampling_rate, size_t fperiod, const char *fn)
{
   HTS_File *fp = HTS_fopen_from_fn(fn, "r");
   HTS_Label_load(label, sampling_rate, fperiod, fp);
   HTS_fclose(fp);
}

/* HTS_Label_load_from_strings: load label from strings */
void HTS_Label_load_from_strings(HTS_Label * label, size_t sampling_rate, size_t fperiod, char **lines, size_t num_lines)
{
   char buff[HTS_MAXBUFLEN];
   HTS_LabelString *lstring = NULL;
   size_t i;
   size_t data_index;
   double start, end;
   const double rate = (double) sampling_rate / ((double) fperiod * 1e+7);

   if (label->head || label->size != 0) {
      HTS_error(1, "HTS_Label_load_from_fp: label list is not initialized.\n");
      return;
   }
   /* copy label */
   for (i = 0; i < num_lines; i++) {
      if (!isgraph((int) lines[i][0]))
         break;
      label->size++;

      if (lstring) {
         lstring->next = (HTS_LabelString *) HTS_calloc(1, sizeof(HTS_LabelString));
         lstring = lstring->next;
      } else {                  /* first time */
         lstring = (HTS_LabelString *) HTS_calloc(1, sizeof(HTS_LabelString));
         label->head = lstring;
      }
      RHVoice_parsed_label_string_init(&(lstring->parsed));
      data_index = 0;
      if (isdigit_string(lines[i])) {   /* has frame infomation */
         HTS_get_token_from_string(lines[i], &data_index, buff);
         start = atof(buff);
         HTS_get_token_from_string(lines[i], &data_index, buff);
         end = atof(buff);
         HTS_get_token_from_string(lines[i], &data_index, buff);
         lstring->name = HTS_strdup(buff);
         lstring->start = rate * start;
         lstring->end = rate * end;
      } else {
         lstring->start = -1.0;
         lstring->end = -1.0;
         lstring->name = HTS_strdup(lines[i]);
      }
      lstring->dur_mod=1.0;
      lstring->next = NULL;
      if(!RHVoice_parse_label_string(lstring->name,&(lstring->parsed)))
        HTS_error(1,"Cannot parse label string\n");
   }
   HTS_Label_check_time(label);
}

/* HTS_Label_get_size: get number of label string */
size_t HTS_Label_get_size(HTS_Label * label)
{
   return label->size;
}

/* HTS_Label_get_string: get label string */
const char *HTS_Label_get_string(HTS_Label * label, size_t index)
{
   size_t i;
   HTS_LabelString *lstring = label->head;

   for (i = 0; i < index && lstring; i++)
      lstring = lstring->next;
   if (!lstring)
      return NULL;
   return lstring->name;
}

const RHVoice_parsed_label_string* HTS_Label_get_parsed(HTS_Label * label, size_t index)
{
   size_t i;
   HTS_LabelString *lstring = label->head;

   for (i = 0; i < index && lstring; i++)
      lstring = lstring->next;
   if (!lstring)
      return NULL;
   return &(lstring->parsed);
}

/* HTS_Label_get_start_frame: get start frame */
double HTS_Label_get_start_frame(HTS_Label * label, size_t index)
{
   size_t i;
   HTS_LabelString *lstring = label->head;

   for (i = 0; i < index && lstring; i++)
      lstring = lstring->next;
   if (!lstring)
      return -1.0;
   return lstring->start;
}

/* HTS_Label_get_end_frame: get end frame */
double HTS_Label_get_end_frame(HTS_Label * label, size_t index)
{
   size_t i;
   HTS_LabelString *lstring = label->head;

   for (i = 0; i < index && lstring; i++)
      lstring = lstring->next;
   if (!lstring)
      return -1.0;
   return lstring->end;
}

double HTS_Label_get_dur_mod(HTS_Label * label, size_t index)
{
   size_t i;
   HTS_LabelString *lstring = label->head;

   for (i = 0; i < index && lstring; i++)
      lstring = lstring->next;
   if (!lstring)
      return 1.0;
   return lstring->dur_mod;
}


/* HTS_Label_clear: free label */
void HTS_Label_clear(HTS_Label * label)
{
   HTS_LabelString *lstring, *next_lstring;

   for (lstring = label->head; lstring; lstring = next_lstring) {
      next_lstring = lstring->next;
      HTS_free(lstring->name);
      RHVoice_parsed_label_string_clear(&(lstring->parsed));
      HTS_free(lstring);
   }
   HTS_Label_initialize(label);
}

HTS_LABEL_C_END;

#endif                          /* !HTS_LABEL_C */
