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.sinusoidal.test;
  
  import java.io.IOException;
  import java.util.Arrays;
  
  import marytts.signalproc.sinusoidal.Sinusoid;
  import marytts.util.io.FileUtils;
  import marytts.util.math.ArrayUtils;
  import marytts.util.math.MathUtils;
  import marytts.util.signal.SignalProcUtils;
  
  /**
   * This class combines SinusoidsTester and NoiseTester classes
   * You can simply give a SinusoidsTester object and NoiseTester object
   * and generate the superposition of the outputs of the two objects,
   * i.e. multiple sinusoids located at desired instants of time plus white or pink noise
   * with desired bandwidth at desired time instants
   * Using this class one can generate fairly complicated yet parametric test signals
   *
   * @author Oytun T&uumlrk
   **/
  public class SinusoidsNoiseTester extends BaseTester {
      public SinusoidsNoiseTester(SinusoidsTester s, NoiseTester n) {
          assert s.fs == n.fs;
          fs = s.fs;
  
          int i;
          int maxLen = 0;
          if (s.signal != null)
              maxLen = s.signal.length;
  
          if (n.signal != null && n.signal.length > maxLen)
              maxLen = n.signal.length;
  
          signal = new double[maxLen];
          pitchMarks = null;
  
          Arrays.fill(signal, 0.0);
  
          if (s.signal != null) {
              System.arraycopy(s.signal, 0, signal, 0, s.signal.length);
  
              //System.out.println("1: " + String.valueOf(MathUtils.getAbsMax(signal)));
  
              if (n.signal != null) {
                  for (i = 0; i < n.signal.length; i++)
                      signal[i] += n.signal[i];
              }
  
              //System.out.println("2: " + String.valueOf(MathUtils.getAbsMax(signal)));
  
              for (i = 0; i < signal.length; i++)
                  signal[i] *= 0.5;
  
              //System.out.println("3: " + String.valueOf(MathUtils.getAbsMax(signal)));
  
              if (s.pitchMarks != null) {
                  if (s.pitchMarks[s.pitchMarks.length - 1] >= maxLen - 1) //Everything is covered by sinusoids so no need to worry about noise part
                  {
                      pitchMarks = ArrayUtils.copy(s.pitchMarks);
                      f0s = ArrayUtils.copy(s.f0s);
                  } else //We need some extra fixed rate marks to cover all signal
                  {
                      int maxT0 = SignalProcUtils.time2sample(1.0 / NoiseTester.FIXED_F0_NOISE, fs);
                      int pitchMarksLen = s.pitchMarks.length;
                      int currInd;
  
                      if (n.pitchMarks != null) {
                          int noiseInd = n.pitchMarks.length - 1;
  
                          //Compute how much extra we will need:
                          while (n.pitchMarks[noiseInd] - s.pitchMarks[s.pitchMarks.length - 1] > maxT0) {
                              noiseInd--;
                              if (noiseInd < 0) {
                                  noiseInd = 0;
                                  break;
                              }
                          }
  
                          pitchMarksLen += n.pitchMarks.length - noiseInd;
  
                          //Check if there is still a gap between the sinusoid end and noise start:
                          if (noiseInd == 0) {
                              currInd = n.pitchMarks[0];
                              while (currInd - s.pitchMarks[s.pitchMarks.length - 1] > maxT0) {
                                  pitchMarksLen++;
                                  currInd -= maxT0;
                              }
                          }
  
                          pitchMarks = new int[pitchMarksLen];
  
                          System.arraycopy(s.pitchMarks, 0, pitchMarks, 0, s.pitchMarks.length);
  
                          for (i = s.pitchMarks.length; i < s.pitchMarks.length + n.pitchMarks.length - noiseInd; i++)
                              pitchMarks[i] = n.pitchMarks[i - s.pitchMarks.length + noiseInd];
  
                          for (i = s.pitchMarks.length + n.pitchMarks.length - noiseInd; i < pitchMarksLen; i++)
                              pitchMarks[i] = Math.min(pitchMarks[i - 1] + maxT0, maxLen - 1);
                      } else //Noise pitch marks do not exist so just generate extra marks at the end to cover all signal
                      {
                          currInd = s.pitchMarks[s.pitchMarks.length - 1];
                          while (maxLen - currInd > maxT0) {
                              pitchMarksLen++;
                              currInd += maxT0;
                          }
  
                          pitchMarks = new int[pitchMarksLen];
  
                          System.arraycopy(s.pitchMarks, 0, pitchMarks, 0, s.pitchMarks.length);
  
                          for (i = s.pitchMarks.length; i < pitchMarksLen; i++)
                              pitchMarks[i] = Math.min(pitchMarks[i - 1] + maxT0, maxLen - 1);
  
                          float lastTime = SignalProcUtils.sample2time(pitchMarks[pitchMarks.length - 1], fs);
                          int numfrm = (int) Math.floor((lastTime - 0.5 * ws) / ss + 0.5);
                          f0s = new double[numfrm];
                          System.arraycopy(s.f0s, 0, f0s, 0, s.f0s.length);
                          for (i = s.f0s.length; i < numfrm; i++)
                              f0s[i] = NoiseTester.FIXED_F0_NOISE;
                      }
                  }
              } else //Generate fixed pitch marks all along the signal
              {
                  int maxT0 = SignalProcUtils.time2sample(1.0 / NoiseTester.FIXED_F0_NOISE, fs);
                  int numPitchMarks = (int) (Math.floor(((double) maxLen) / maxT0 + 0.5)) + 1;
                  pitchMarks = new int[numPitchMarks];
                  for (i = 0; i < numPitchMarks; i++)
                      pitchMarks[i] = Math.min(i * maxT0, maxLen - 1);
  
                  float lastTime = SignalProcUtils.sample2time(pitchMarks[pitchMarks.length - 1], fs);
                  int numfrm = (int) Math.floor((lastTime - 0.5 * ws) / ss + 0.5);
                  f0s = new double[numfrm];
                  Arrays.fill(f0s, NoiseTester.FIXED_F0_NOISE);
              }
          } else {
              System.arraycopy(n.signal, 0, signal, 0, n.signal.length);
  
              if (n.pitchMarks != null) {
                  pitchMarks = ArrayUtils.copy(n.pitchMarks);
                  f0s = ArrayUtils.copy(n.f0s);
              }
          }
      }
  
      public static void main(String[] args) throws IOException {
          int i, numSins, numNoises;
  
          SinusoidsTester s = null;
          NoiseTester n = null;
          SinusoidsNoiseTester h = null;
  
          //Sinus part
          numSins = 5;
          float[] sinFreqs = new float[numSins];
          sinFreqs[0] = 120.0f;
          sinFreqs[1] = 230.0f;
          sinFreqs[2] = 500.0f;
          sinFreqs[3] = 1100.0f;
          sinFreqs[4] = 1500.0f;
  
          Sinusoid[] sins = new Sinusoid[numSins];
          for (i = 0; i < numSins; i++)
              sins[i] = new Sinusoid(100.0f, sinFreqs[i], 0.0f);
  
          s = new SinusoidsTester(sins);
          //
  
          //Noise part
          numNoises = 1;
          float[][] freqs = new float[numNoises][];
          float[] amps = new float[numNoises];
          for (i = 0; i < numNoises; i++)
              freqs[i] = new float[2];
  
          freqs[0][0] = 2000;
          freqs[0][1] = 4000;
          amps[0] = 100.0f;
  
          n = new NoiseTester(freqs, amps);
          //
  
          h = new SinusoidsNoiseTester(s, n);
  
          if (args.length > 1)
              h.write(args[0], args[1]);
          else
              h.write(args[0]);
  
          System.out.println(String.valueOf(MathUtils.getAbsMax(h.signal)) + " " + MathUtils.getAbsMax(s.signal) + " " + MathUtils.getAbsMax(n.signal));
  
          int[] pitchMarks = FileUtils.readFromBinaryFile(args[1]);
          for (i = 0; i < pitchMarks.length; i++)
              System.out.println(String.valueOf(pitchMarks[i]) + " ");
      }
  }
  
  