content: /**
   * Copyright 2007 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.signalproc.process;
  
  import java.util.Arrays;
  
  import marytts.signalproc.window.Window;
  import marytts.util.math.MathUtils;
  import marytts.util.signal.SignalProcUtils;
  
  /**
   * @author oytun.turk
   */
  public class OverlapAddEnergyNormalizer {
      public static double[] normalize(double[] x,
                                       int samplingRate,
                                       double windowSizeInSeconds,
                                       double skipSizeInSeconds,
                                       int windowType,
                                       double targetEnergy) {
          double[] y = new double[x.length];
          double[] w = new double[x.length];
          Arrays.fill(y, 0.0);
          Arrays.fill(w, 0.0);
  
          int ws = (int) Math.floor(windowSizeInSeconds * samplingRate + 0.5);
          if (ws % 2 != 0)
              ws++;
          int half_ws = (int) (ws / 2.0);
          int ss = (int) Math.floor(skipSizeInSeconds * samplingRate + 0.5);
  
          Window win = Window.get(windowType, ws);
          win.normalize(1.0f); //Normalize to sum up to unity
          double[] wgt = new double[ws];
          double[] frm = new double[ws];
  
          int start = 0;
          boolean bLastFrame = false;
          double frmEn, gain;
          int i;
          while (true) {
              if (start + ws - 1 >= x.length - 1)
                  bLastFrame = true;
  
              wgt = win.getCoeffs();
              if (start == 0) //First frame
                  Arrays.fill(wgt, 0, half_ws - 1, 1.0);
              else if (bLastFrame)
                  Arrays.fill(wgt, half_ws, ws - 1, 1.0);
  
              Arrays.fill(frm, 0.0);
              System.arraycopy(x, start, frm, 0, Math.min(ws, x.length - start));
  
              frm = MathUtils.multiply(frm, wgt);
  
              frmEn = SignalProcUtils.energy(frm);
              gain = Math.sqrt(targetEnergy / frmEn);
              System.out.println(String.valueOf(gain));
  
              frm = MathUtils.multiply(frm, gain);
              frm = MathUtils.multiply(frm, wgt);
  
              for (i = 0; i < ws; i++) {
                  if (i + start >= y.length) {
                      bLastFrame = true;
                      break;
                  }
  
                  y[i + start] += frm[i];
                  w[i + start] += wgt[i] * wgt[i];
              }
  
              if (bLastFrame)
                  break;
  
              start += ss;
          }
  
          for (i = 0; i < y.length; i++) {
              if (w[i] > 0.0)
                  y[i] /= w[i];
          }
  
  
          return y;
      }
  }
  
  