package org.kc7bfi.jflac; /** * libFLAC - Free Lossless Audio Codec library * Copyright (C) 2000,2001,2002,2003 Josh Coalson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * Fixed Predictor utility class. * * @author kc7bfi */ public class FixedPredictor { private static final double M_LN2 = 0.69314718055994530942; /** * Compute the best predictor order. * * @param data * @param dataLen * @param residualBitsPerSample * @return */ public static int computeBestPredictor(int[] data, int dataLen, double[] residualBitsPerSample) { int lastError0 = data[-1]; int lastError1 = data[-1] - data[-2]; int lastError2 = lastError1 - (data[-2] - data[-3]); int lastError3 = lastError2 - (data[-2] - 2 * data[-3] + data[-4]); int error, save; int totalError0 = 0, totalError1 = 0, totalError2 = 0, totalError3 = 0, totalError4 = 0; int i, order; for (i = 0; i < dataLen; i++) { error = data[i]; totalError0 += Math.abs(error); save = error; error -= lastError0; totalError1 += Math.abs(error); lastError0 = save; save = error; error -= lastError1; totalError2 += Math.abs(error); lastError1 = save; save = error; error -= lastError2; totalError3 += Math.abs(error); lastError2 = save; save = error; error -= lastError3; totalError4 += Math.abs(error); lastError3 = save; } if (totalError0 < Math.min(Math.min(Math.min(totalError1, totalError2), totalError3), totalError4)) order = 0; else if (totalError1 < Math.min(Math.min(totalError2, totalError3), totalError4)) order = 1; else if (totalError2 < Math.min(totalError3, totalError4)) order = 2; else if (totalError3 < totalError4) order = 3; else order = 4; // Estimate the expected number of bits per residual signal sample. // 'total_error*' is linearly related to the variance of the residual // signal, so we use it directly to compute E(|x|) residualBitsPerSample[0] = (double) ((totalError0 > 0) ? Math.log(M_LN2 * (double) totalError0 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[1] = (double) ((totalError1 > 0) ? Math.log(M_LN2 * (double) totalError1 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[2] = (double) ((totalError2 > 0) ? Math.log(M_LN2 * (double) totalError2 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[3] = (double) ((totalError3 > 0) ? Math.log(M_LN2 * (double) totalError3 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[4] = (double) ((totalError4 > 0) ? Math.log(M_LN2 * (double) totalError4 / (double) dataLen) / M_LN2 : 0.0); return order; } /** * Compute the best predictor order. * * @param data * @param dataLen * @param residualBitsPerSample * @return */ public static int computeBestPredictorWide(int[] data, int dataLen, double[] residualBitsPerSample) { int lastError0 = data[-1]; int lastError1 = data[-1] - data[-2]; int lastError2 = lastError1 - (data[-2] - data[-3]); int lastError3 = lastError2 - (data[-2] - 2 * data[-3] + data[-4]); int error, save; // totalError* are 64-bits to avoid overflow when encoding // erratic signals when the bits-per-sample and blocksize are // large. long totalError0 = 0, totalError1 = 0, totalError2 = 0, totalError3 = 0, totalError4 = 0; int i, order; for (i = 0; i < dataLen; i++) { error = data[i]; totalError0 += Math.abs(error); save = error; error -= lastError0; totalError1 += Math.abs(error); lastError0 = save; save = error; error -= lastError1; totalError2 += Math.abs(error); lastError1 = save; save = error; error -= lastError2; totalError3 += Math.abs(error); lastError2 = save; save = error; error -= lastError3; totalError4 += Math.abs(error); lastError3 = save; } if (totalError0 < Math.min(Math.min(Math.min(totalError1, totalError2), totalError3), totalError4)) order = 0; else if (totalError1 < Math.min(Math.min(totalError2, totalError3), totalError4)) order = 1; else if (totalError2 < Math.min(totalError3, totalError4)) order = 2; else if (totalError3 < totalError4) order = 3; else order = 4; // Estimate the expected number of bits per residual signal sample. // 'total_error*' is linearly related to the variance of the residual // signal, so we use it directly to compute E(|x|) // with VC++ you have to spoon feed it the casting residualBitsPerSample[0] = (double) ((totalError0 > 0) ? Math.log(M_LN2 * (double) (long) totalError0 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[1] = (double) ((totalError1 > 0) ? Math.log(M_LN2 * (double) (long) totalError1 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[2] = (double) ((totalError2 > 0) ? Math.log(M_LN2 * (double) (long) totalError2 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[3] = (double) ((totalError3 > 0) ? Math.log(M_LN2 * (double) (long) totalError3 / (double) dataLen) / M_LN2 : 0.0); residualBitsPerSample[4] = (double) ((totalError4 > 0) ? Math.log(M_LN2 * (double) (long) totalError4 / (double) dataLen) / M_LN2 : 0.0); return order; } /** * Compute the residual from the compressed signal. * * @param data * @param dataLen * @param order * @param residual */ public static void computeResidual(int[] data, int dataLen, int order, int[] residual) { int idataLen = (int) dataLen; switch (order) { case 0: for (int i = 0; i < idataLen; i++) { residual[i] = data[i]; } break; case 1: for (int i = 0; i < idataLen; i++) { residual[i] = data[i] - data[i - 1]; } break; case 2: for (int i = 0; i < idataLen; i++) { /* == data[i] - 2*data[i-1] + data[i-2] */ residual[i] = data[i] - (data[i - 1] << 1) + data[i - 2]; } break; case 3: for (int i = 0; i < idataLen; i++) { /* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */ residual[i] = data[i] - (((data[i - 1] - data[i - 2]) << 1) + (data[i - 1] - data[i - 2])) - data[i - 3]; } break; case 4: for (int i = 0; i < idataLen; i++) { /* == data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4] */ residual[i] = data[i] - ((data[i - 1] + data[i - 3]) << 2) + ((data[i - 2] << 2) + (data[i - 2] << 1)) + data[i - 4]; } break; default: } } /** * Restore the signal from the fixed predictor. * * @param residual The residual data * @param dataLen The length of residual data * @param order The preicate order * @param data The restored signal (output) * @param startAt The starting position in the data array */ public static void restoreSignal(int[] residual, int dataLen, int order, int[] data, int startAt) { int idataLen = (int) dataLen; switch (order) { case 0: for (int i = 0; i < idataLen; i++) { data[i + startAt] = residual[i]; } break; case 1: for (int i = 0; i < idataLen; i++) { data[i + startAt] = residual[i] + data[i + startAt - 1]; } break; case 2: for (int i = 0; i < idataLen; i++) { /* == residual[i] + 2*data[i-1] - data[i-2] */ data[i + startAt] = residual[i] + (data[i + startAt - 1] << 1) - data[i + startAt - 2]; } break; case 3: for (int i = 0; i < idataLen; i++) { /* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */ data[i + startAt] = residual[i] + (((data[i + startAt - 1] - data[i + startAt - 2]) << 1) + (data[i + startAt - 1] - data[i + startAt - 2])) + data[i + startAt - 3]; } break; case 4: for (int i = 0; i < idataLen; i++) { /* == residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4] */ data[i + startAt] = residual[i] + ((data[i + startAt - 1] + data[i + startAt - 3]) << 2) - ((data[i + startAt - 2] << 2) + (data[i + startAt - 2] << 1)) - data[i + startAt - 4]; } break; default: } } }