text: /*
   * Copyright 1999-2002 Carnegie Mellon University.  
   * Portions Copyright 2002 Sun Microsystems, Inc.  
   * Portions Copyright 2002 Mitsubishi Electric Research Laboratories.
   * All Rights Reserved.  Use is subject to license terms.
   * 
   * See the file "license.terms" for information on usage and
   * redistribution of this file, and for a DISCLAIMER OF ALL 
   * WARRANTIES.
   *
   */
  package edu.cmu.sphinx.frontend.feature;
  
  import edu.cmu.sphinx.frontend.*;
  
  /**
   * Computes the delta and double delta of input cepstrum (or plp or ...). The delta is the first order derivative and
   * the double delta (a.k.a. delta delta) is the second order derivative of the original cepstrum. They help model the
   * speech signal dynamics. The output data is a {@link FloatData} object with a float array of size three times the
   * original cepstrum, formed by the concatenation of cepstra, delta cepstra, and double delta cepstra. The output is the
   * feature vector used by the decoder. Figure 1 shows the arrangement of the output feature data array:
   * <p>
   * <img alt="Layout of features" src="doc-files/feature.jpg"> <br> <b>Figure 1: Layout of the returned features. </b>
   * <p>
   * Suppose that the original cepstrum has a length of N, the first N elements of the feature are just the original
   * cepstrum, the second N elements are the delta of the cepstrum, and the last N elements are the double delta of the
   * cepstrum.
   * <p>
   * Figure 2 below shows pictorially the computation of the delta and double delta of a cepstrum vector, using the last 3
   * cepstra and the next 3 cepstra. <img alt="Delta computation" src="doc-files/deltas.jpg"> <br> <b>Figure 2: Delta and double delta vector
   * computation. </b>
   * <p>
   * Referring to Figure 2, the delta is computed by subtracting the cepstrum that is two frames behind of the current
   * cepstrum from the cepstrum that is two frames ahead of the current cepstrum. The computation of the double delta is
   * similar. It is computed by subtracting the delta cepstrum one time frame behind from the delta cepstrum one time
   * frame ahead. Replacing delta cepstra with cepstra, this works out to a formula involving the cepstra that are one and
   * three behind and after the current cepstrum.
   */
  public class DeltasFeatureExtractor extends AbstractFeatureExtractor {
  
      public DeltasFeatureExtractor(int window) {
          super(window);
      }
  
      public DeltasFeatureExtractor( ) {
      }
      
      /**
       * Computes the next feature. Advances the pointers as well.
       *
       * @return the feature Data computed
       */
      @Override
      protected Data computeNextFeature() {
  
      	int jp1 = (currentPosition - 1 + cepstraBufferSize) % cepstraBufferSize;
          int jp2 = (currentPosition - 2 + cepstraBufferSize) % cepstraBufferSize;
          int jp3 = (currentPosition - 3 + cepstraBufferSize) % cepstraBufferSize;
          int jf1 = (currentPosition + 1) % cepstraBufferSize;
          int jf2 = (currentPosition + 2) % cepstraBufferSize;
          int jf3 = (currentPosition + 3) % cepstraBufferSize;
          
      	DoubleData currentCepstrum = cepstraBuffer[currentPosition];
          double[] mfc3f = cepstraBuffer[jf3].getValues();
          double[] mfc2f = cepstraBuffer[jf2].getValues();
          double[] mfc1f = cepstraBuffer[jf1].getValues();
          double[] current = currentCepstrum.getValues();
          double[] mfc1p = cepstraBuffer[jp1].getValues();
          double[] mfc2p = cepstraBuffer[jp2].getValues();
          double[] mfc3p = cepstraBuffer[jp3].getValues();
          float[] feature = new float[current.length * 3];
  
          currentPosition = (currentPosition + 1) % cepstraBufferSize;
  
          // CEP; copy all the cepstrum data
          int j = 0;
          for (double val : current) {
              feature[j++] = (float)val;
          }
          // System.arraycopy(current, 0, feature, 0, j);
          // DCEP: mfc[2] - mfc[-2]
          for (int k = 0; k < mfc2f.length; k++) {
              feature[j++] = (float) (mfc2f[k] - mfc2p[k]);
          }
          // D2CEP: (mfc[3] - mfc[-1]) - (mfc[1] - mfc[-3])
          for (int k = 0; k < mfc3f.length; k++) {
              feature[j++] = (float) ((mfc3f[k] - mfc1p[k]) - (mfc1f[k] - mfc3p[k]));
          }
          return (new FloatData(feature,
                  currentCepstrum.getSampleRate(),
                  currentCepstrum.getFirstSampleNumber()));
      }
  }
  