content: /* ----------------------------------------------------------------- */
  /*           The HMM-Based Speech Synthesis Engine "hts_engine API"  */
  /*           developed by HTS Working Group                          */
  /*           http://hts-engine.sourceforge.net/                      */
  /* ----------------------------------------------------------------- */
  /*                                                                   */
  /*  Copyright (c) 2001-2010  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.                                       */
  /* ----------------------------------------------------------------- */
  /**
   * Copyright 2011 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, version 3 of the License.
   * <p/>
   * 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 Lesser General Public License for more details.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package marytts.htsengine;
  
  import android.util.Log;
  
  import java.io.BufferedInputStream;
  import java.io.BufferedReader;
  import java.io.DataInputStream;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.util.StringTokenizer;
  
  import marytts.features.FeatureDefinition;
  import marytts.server.Mary;
  
  //import org.apache.log4j.Logger;
  
  /**
   * Set of Global Mean and (diagonal) Variance for log f0, mel-cepstrum, bandpass
   * voicing strengths and Fourier magnitudes (
   * <p/>
   * Java port and extension of HTS engine API version 1.04
   * Extension: mixed excitation
   *
   * @author Marcela Charfuelan
   */
  public class GVModelSet {
  
      /**
       * ____________________ GV related variables ____________________
       * GV: Global mean and covariance (diagonal covariance only) it should be inverse for GV method Gradient
       * weight by default is 1.0 but it can be between 0.0-2.0
       */
      private double gvmeanMgc[];
      private double gvcovInvMgc[];
  
      private double gvmeanLf0[];
      private double gvcovInvLf0[];
  
      private double gvmeanStr[];
      private double gvcovInvStr[];
  
      private double gvmeanMag[];
      private double gvcovInvMag[];
  
  
      public double[] getGVmeanMgc() {
          return gvmeanMgc;
      }
  
      public double[] getGVcovInvMgc() {
          return gvcovInvMgc;
      }
  
      public double[] getGVmeanLf0() {
          return gvmeanLf0;
      }
  
      public double[] getGVcovInvLf0() {
          return gvcovInvLf0;
      }
  
      public double[] getGVmeanStr() {
          return gvmeanStr;
      }
  
      public double[] getGVcovInvStr() {
          return gvcovInvStr;
      }
  
      public double[] getGVmeanMag() {
          return gvmeanMag;
      }
  
      public double[] getGVcovInvMag() {
          return gvcovInvMag;
      }
  
  
      public void loadGVModelSet(HMMData htsData, FeatureDefinition featureDef) throws IOException {
      
      /* allocate memory for the arrays and load the data from file */
          int numMSDFlag, numStream, vectorSize, numDurPdf;
          double gvcov;
          DataInputStream data_in;
          InputStream gvStream;
          
      /* Here global variance vectors are loaded from corresponding files */
          int m, i, nmix;
          if (htsData.getUseGV()) {
              // GV for Mgc
              if ((gvStream = htsData.getPdfMgcGVStream()) != null)
                  loadGvFromFile(gvStream, "mgc", htsData.getGvMethodGradient(), htsData.getGvWeightMgc());
  
              // GV for Lf0
              if ((gvStream = htsData.getPdfLf0GVStream()) != null)
                  loadGvFromFile(gvStream, "lf0", htsData.getGvMethodGradient(), htsData.getGvWeightLf0());
  
              // GV for Str
              if ((gvStream = htsData.getPdfStrGVStream()) != null)
                  loadGvFromFile(gvStream, "str", htsData.getGvMethodGradient(), htsData.getGvWeightStr());
  
              // GV for Mag
              if ((gvStream = htsData.getPdfMagGVStream()) != null)
                  loadGvFromFile(gvStream, "mag", htsData.getGvMethodGradient(), htsData.getGvWeightMag());
  
              // gv-switch
              // if( (gvFile=htsData.getSwitchGVFile()) != null)
              //   loadSwitchGvFromFile(gvFile, featureDef, trickyPhones);
  
          }
  
      }
  
  
      private void loadGvFromFile(InputStream gvStream, String par, boolean gradientMethod, double gvWeight) throws IOException {
  
          int numMSDFlag, numStream, vectorSize, numDurPdf;
          DataInputStream data_in;
          int m, i;
  
          data_in = new DataInputStream(new BufferedInputStream(gvStream));
          Log.d(Mary.LOG, "LoadGVModelSet reading model of type '" + par + "' with gvWeight = " + gvWeight);
  
          numMSDFlag = data_in.readInt();
          numStream = data_in.readInt();
          vectorSize = data_in.readInt();
          numDurPdf = data_in.readInt();
  
          if (par.contentEquals("mgc")) {
              gvmeanMgc = new double[vectorSize];
              gvcovInvMgc = new double[vectorSize];
              readBinaryFile(data_in, gvmeanMgc, gvcovInvMgc, vectorSize, gradientMethod, gvWeight);
          } else if (par.contentEquals("lf0")) {
              gvmeanLf0 = new double[vectorSize];
              gvcovInvLf0 = new double[vectorSize];
              readBinaryFile(data_in, gvmeanLf0, gvcovInvLf0, vectorSize, gradientMethod, gvWeight);
          } else if (par.contentEquals("str")) {
              gvmeanStr = new double[vectorSize];
              gvcovInvStr = new double[vectorSize];
              readBinaryFile(data_in, gvmeanStr, gvcovInvStr, vectorSize, gradientMethod, gvWeight);
          } else if (par.contentEquals("mag")) {
              gvmeanMag = new double[vectorSize];
              gvcovInvMag = new double[vectorSize];
              readBinaryFile(data_in, gvmeanMag, gvcovInvMag, vectorSize, gradientMethod, gvWeight);
          }
          data_in.close();
      }
  
      private void readBinaryFile(DataInputStream data_in, double mean[], double ivar[], int vectorSize, boolean gradientMethod, double gvWeight)
              throws IOException {
          int i;
          double var;
          if (gradientMethod) {
              for (i = 0; i < vectorSize; i++) {
                  mean[i] = data_in.readFloat() * gvWeight;
                  var = data_in.readFloat();
                  assert var > 0.0;
                  ivar[i] = 1.0 / var;
              }
          } else {
              for (i = 0; i < vectorSize; i++) {
                  mean[i] = data_in.readFloat() * gvWeight;
                  ivar[i] = data_in.readFloat();
              }
          }
      }
  
  
      public void loadSwitchGvFromFile(String gvFile, FeatureDefinition featDef, PhoneTranslator trickyPhones)
              throws Exception {
  
          //featDef = featDefinition;
          //phTrans = phoneTranslator;
          PhoneTranslator phTrans = trickyPhones;
  
          int i, j, length, state, feaIndex;
          BufferedReader s = null;
          String line, buf, aux;
          StringTokenizer sline;
          //phTrans = phTranslator;
  
  
          assert featDef != null : "Feature Definition was not set";
  
          try {
       /* read lines of tree-*.inf fileName */
              s = new BufferedReader(new InputStreamReader(new FileInputStream(gvFile)));
              Log.i(Mary.LOG, "load: reading " + gvFile);
  
              // skip questions section
              while ((line = s.readLine()) != null) {
                  if (line.indexOf("QS") < 0) break;   /* a new state is indicated by {*}[2], {*}[3], ... */
              }
  
              while ((line = s.readLine()) != null) {
                  if (line.indexOf("{*}") >= 0) {  /* this is the indicator of a new state-tree */
                      aux = line.substring(line.indexOf("[") + 1, line.indexOf("]"));
                      state = Integer.parseInt(aux);
  
                      sline = new StringTokenizer(aux);
           
           /* 1:  gets index node and looks for the node whose idx = buf */
                      buf = sline.nextToken();
           
           /* 2: gets question name and question name val */
                      buf = sline.nextToken();
                      String[] fea_val = buf.split("=");   /* splits featureName=featureValue*/
                      feaIndex = featDef.getFeatureIndex(fea_val[0]);
          
           /* Replace back punctuation values */
           /* what about tricky phones, if using halfphones it would not be necessary */
                      if (fea_val[0].contentEquals("sentence_punc") || fea_val[0].contentEquals("prev_punctuation") || fea_val[0].contentEquals("next_punctuation")) {
                          //System.out.print("CART replace punc: " + fea_val[0] + " = " + fea_val[1]);
                          fea_val[1] = phTrans.replaceBackPunc(fea_val[1]);
                          //System.out.println(" --> " + fea_val[0] + " = " + fea_val[1]);
                      } else if (fea_val[0].contains("tobi_")) {
                          //System.out.print("CART replace tobi: " + fea_val[0] + " = " + fea_val[1]);
                          fea_val[1] = phTrans.replaceBackToBI(fea_val[1]);
                          //System.out.println(" --> " + fea_val[0] + " = " + fea_val[1]);
                      } else if (fea_val[0].contains("phone")) {
                          //System.out.print("CART replace phone: " + fea_val[0] + " = " + fea_val[1]);
                          fea_val[1] = phTrans.replaceBackTrickyPhones(fea_val[1]);
                          //System.out.println(" --> " + fea_val[0] + " = " + fea_val[1]);
                      }
  
                      // add featureName and featureValue to the switch off gv phones
  
                  }
              } /* while */
              if (s != null)
                  s.close();
  
          } catch (FileNotFoundException e) {
              Log.d(Mary.LOG, "FileNotFoundException: " + e.getMessage());
              throw new FileNotFoundException("LoadTreeSet: " + e.getMessage());
          }
  
      }
  
  
  }
  