All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.javaflacencoder.LPC Maven / Gradle / Ivy

Go to download

javaFlacEncoder is a pure java implementation of a FLAC encoder library. It is designed to allow third-party java applications to enable flac encoding without resorting to use of JNI or scripted file conversions. Additionally, a basic console wav->flac encoding tool is included as part of this package. Original project can be found here: http://javaflacencoder.sourceforge.net/

The newest version!
/*
 * Copyright (C) 2010  Preston Lacey http://javaflacencoder.sourceforge.net/
 * All Rights Reserved.
 *
 * This library 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package net.sourceforge.javaflacencoder;

/**
 * This class is used to calculate LPC Coefficients for a FLAC stream.
 *
 * @author Preston Lacey
 */
public class LPC {
  /** The error calculated by the LPC algorithm */
  protected double rawError;
  /** The coefficients as calculated by the LPC algorithm */
  protected double[] rawCoefficients;
  private double[] tempCoefficients;
  /** The order of this LPC calculation */
  protected int order;
  static int[] tempSum = null;
  /**
   * Constructor creates an LPC object of the given order.
   * @param order Order for this LPC calculation.
   */
  public LPC(int order) {
    this.order = order;
    rawError = 0;
    rawCoefficients = new double[order+1];
    tempCoefficients = new double[order+1];
  }
  /**
   * Get this LPC object's order
   * @return order used for this LPC calculation.
   */
  public int getOrder () { return order; }
  /**
   * Get the error for this LPC calculation
   * @return lpc error
   */
  public double getError() { return rawError; }

  /**
   * Get the calculated LPC Coefficients as an array.
   * @return lpc coefficients in an array.
   */
  public double[] getCoefficients() { return rawCoefficients; }

  /**
   * Calculate an LPC using the given Auto-correlation data. Static method
   * used since this is slightly faster than a more strictly object-oriented
   * approach.
   *
   * @param lpc LPC to calculate
   * @param R Autocorrelation data to use
   */
  public static void calculate(LPC lpc, long[] R) {
    int coeffCount = lpc.order;

    //calculate first iteration directly
    double[] A = lpc.rawCoefficients;
    for(int i = 0; i < coeffCount+1; i++) A[i] = 0.0;
    A[0] = 1;
    double E = R[0];

    //calculate remaining iterations

    if(R[0] == 0) {
      for(int i = 0; i < coeffCount+1; i++)
        A[i] = 0.0;
    }
    else {
      double[] ATemp = lpc.tempCoefficients;
      for(int i = 0; i < coeffCount+1; i++) ATemp[i] = 0.0;

      for(int k = 0; k < coeffCount; k++) {
        double lambda = 0.0;
        double temp = 0;
        for(int j = 0; j <= k; j++) {
          temp += A[j]*R[k+1-j];
        }
        lambda = -temp/E;

        for(int i = 0; i <= k+1; i++) {
          ATemp[i] = A[i]+lambda*A[k+1-i];
        }
        System.arraycopy(ATemp, 0, A, 0, coeffCount+1);
        E = (1-lambda*lambda)*E;
      }
    }
    lpc.rawError = E;
  }

  /**
   * Calculate an LPC using a prior order LPC's values to save calculations.
   *
   * @param lpc LPC to calculate
   * @param R Auto-correlation data to use.
   * @param priorLPC Prior order LPC to use(may be any order lower than our
   * target LPC)
   *
   */
  public static void calculateFromPrior(LPC lpc, long[] R, LPC priorLPC) {
    int coeffCount = lpc.order;

    //calculate first iteration directly
    double[] A = lpc.rawCoefficients;
    for(int i = 0; i < coeffCount+1; i++) A[i] = 0.0;
    A[0] = 1;
    double E = R[0];
    int startIter = 0;
    if(priorLPC != null && priorLPC.order < lpc.order) {
      startIter = priorLPC.order;
      E = priorLPC.rawError;
      System.arraycopy(priorLPC.rawCoefficients, 0, A, 0, startIter+1);
    }
    //calculate remaining iterations
    if(R[0] == 0) {
      for(int i = 0; i < coeffCount+1; i++)
        A[i] = 0.0;
    }
    else {
      double[] ATemp = lpc.tempCoefficients;
      for(int i = 0; i < coeffCount+1; i++) ATemp[i] = 0.0;

      for(int k = startIter; k < coeffCount; k++) {
        double lambda = 0.0;
        double temp = 0.0;
        for(int j = 0; j <= k; j++) {
          temp -= A[j]*R[k-j+1];
        }
        lambda = temp/E;

        for(int i = 0; i <= k+1; i++) {
          ATemp[i] = A[i]+lambda*A[k+1-i];
        }
        System.arraycopy(ATemp, 0, A, 0, coeffCount+1);
        E = (1-lambda*lambda)*E;
      }
    }
    lpc.rawError = E;
  }

  /**
   * Create auto-correlation coefficients(up to a maxOrder of 32).
   * @param R Array to put results in.
   * @param samples Samples to calculate the auto-correlation for.
   * @param count number of samples to use
   * @param start index of samples array to start at
   * @param increment number of indices to increment between valid samples(for
   * interleaved arrays)
   * @param maxOrder maximum order to calculate.
   */
  public static void createAutoCorrelation(long[] R, int []samples, int count,
      int start, int increment, int maxOrder) {
    if(increment == 1 && start == 0) {
      for(int i = 0; i <= maxOrder; i++) {
        R[i] = 0;
        long temp = 0;
        for(int j = 0; j < count-i; j++) {
          temp += (long)samples[j]*(long)samples[j+i];
        }
        R[i] += temp;
      }
    }
    else {
      for(int i = 0; i <= maxOrder; i++) {
        R[i] = 0;
        int baseIndex = increment*i;
        long temp = 0;
        int innerLimit = (count-i)*increment;
        for(int j = start; j < innerLimit; j+=increment) {
          temp += (long)samples[j]*(long)samples[j+baseIndex];
        }
        R[i] += temp;
      }
    }
  }
 
  /**
   * Apply a window function to sample data
   * @param samples Samples to apply window to. Values in this array are left
   * unaltered.
   * @param count number of samples to use
   * @param start index of samples array to start at
   * @param increment number of indices to increment between valid samples(for
   * interleaved arrays)
   * @param windowedSamples array containing windowed values. Return values
   * are packed(increment of one).
   *
   */
  public static void window(int[] samples, int count, int start, int increment,
      int[] windowedSamples) {
    int[] values = windowedSamples;
    int loopCount = 0;
    float halfway = count/2.0f;
    float hth = halfway*halfway;
    float windowCount = -halfway;
    int limit = count*increment+start;
    for(int i = start; i < limit; i+=increment) {
      //float innerCount = (windowCount < 0) ? -windowCount:windowCount;
      float innerCountSquared = windowCount*windowCount;
      windowCount++;
      //double val = 1.0-(double)(innerCount/halfway);
      float val = 1.0f-( innerCountSquared/hth );
      double temp = ((double)samples[i])*val;
      temp = (temp >0) ? temp+0.5:temp-0.5;
      values[loopCount++] = (int)temp;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy