content: /**
   * Copyright 2004-2006 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.analysis;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import marytts.signalproc.analysis.FrameBasedAnalyser.FrameAnalysisResult;
  import marytts.signalproc.process.PitchFrameProvider;
  import marytts.signalproc.window.DynamicWindow;
  import marytts.util.data.DoubleDataSource;
  
  
  /**
   * @author Marc Schr&ouml;der
   *         <p/>
   *         The base class for all frame-based signal analysis algorithms.
   */
  public abstract class PitchFrameAnalyser extends PitchFrameProvider {
      protected DynamicWindow analysisWindow;
  
      /**
       * Array containing the analysis results, filled by analyseAllFrames().
       * Can be used for future reference to the results.
       */
      protected FrameAnalysisResult[] analysisResults;
  
      /**
       * Initialise a PitchFrameAnalyser.
       *
       * @param signal       the signal source to read from
       * @param pitchmarks   the source of the pitchmarks, in seconds from the start of signal
       * @param windowType   type of analysis window to use, @see{de.dfki.signalproc.window.Window#getAvailableTypes()}
       * @param samplingRate the number of samples in one second.
       */
      public PitchFrameAnalyser(DoubleDataSource signal, DoubleDataSource pitchmarks, int windowType, int samplingRate) {
          this(signal, pitchmarks, windowType, samplingRate, 1, 1);
      }
  
      /**
       * Create a new PitchFrameAnalyser with a configurable number of pitch periods per frame
       * and pitch periods to shift by.
       *
       * @param signal       audio signal
       * @param pitchmarks   an array of pitchmarks; each pitch mark is in seconds from signal start
       * @param windowType   type of analysis window to use, @see{de.dfki.signalproc.window.Window#getAvailableTypes()}
       * @param samplingRate number of samples per second in signal
       * @param framePeriods number of periods that each frame should contain
       * @param shiftPeriods number of periods that frames should be shifted by
       */
      public PitchFrameAnalyser(DoubleDataSource signal, DoubleDataSource pitchmarks,
                                int windowType,
                                int samplingRate, int framePeriods, int shiftPeriods) {
          super(signal, pitchmarks, new DynamicWindow(windowType), samplingRate, framePeriods, shiftPeriods);
      }
  
      /**
       * The public method to call in order to trigger the analysis of the next frame.
       *
       * @return the analysis result, or null if no part of the signal is left to analyse.
       */
      public FrameAnalysisResult analyseNextFrame() {
          double[] frame = getNextFrame();
          if (frame == null) return null;
          analysisWindow.applyInline(frame, 0, frame.length);
          Object analysisResult = analyse(frame);
          return constructAnalysisResult(analysisResult);
      }
  
      /**
       * Analyse the entire signal as frames. Stop as soon as the first frame reaches
       * or passes the end of the signal. Repeated access to this method returns
       * a stored version of the results.
       *
       * @return an array containing all frame analysis results.
       */
      public FrameAnalysisResult[] analyseAllFrames() {
          if (analysisResults == null) {
              ArrayList results = new ArrayList();
              FrameAnalysisResult oneResult;
              while ((oneResult = analyseNextFrame()) != null) {
                  results.add(oneResult);
              }
              analysisResults = (FrameAnalysisResult[]) results.toArray(new FrameAnalysisResult[0]);
          }
          return analysisResults;
      }
  
      /**
       * Analyse the currently available input signal as frames. This method
       * is intended for live signals such as microphone data.
       * Stop when the amount of data available from the input is
       * less than one frame length.
       * Repeated access to this method will read new data if new data has
       * become available in the meantime.
       *
       * @return an array containing the frame analysis results for the data
       * that is currently available, or an empty array if no new data is available.
       */
      public FrameAnalysisResult[] analyseAvailableFrames() {
          List results = new ArrayList();
          FrameAnalysisResult oneResult;
          while (signal.available() >= frameLength) {
              oneResult = analyseNextFrame();
              assert oneResult != null;
              results.add(oneResult);
          }
          return (FrameAnalysisResult[]) results.toArray(new FrameAnalysisResult[0]);
      }
  
      /**
       * Apply this PitchFrameAnalyser to the given data.
       *
       * @param frame the data to analyse, which is expected to be the number of
       *              pitch periods requested from this PitchFrameAnalyser, @see{#getFramePeriods()}.
       * @return An analysis result. The data type depends on the concrete analyser.
       * @throws IllegalArgumentException if frame does not have the prescribed length
       */
      public abstract Object analyse(double[] frame);
  
      protected FrameAnalysisResult constructAnalysisResult(Object analysisResult) {
          return new FrameAnalysisResult(frame, getFrameStartTime(), analysisResult);
      }
  
  }
  
  