Home | History | Annotate | Download | only in audio
      1 package com.android.cts.verifier.audio;
      2 
      3 import org.apache.commons.math.complex.Complex;
      4 import org.apache.commons.math.stat.descriptive.moment.Mean;
      5 import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
      6 import org.apache.commons.math.stat.descriptive.rank.Median;
      7 import org.apache.commons.math.transform.FastFourierTransformer;
      8 
      9 /**
     10  * This class contains util functions used in the WavAnalyzer.
     11  */
     12 public class Util {
     13 
     14   /**
     15    * Convert time in second to sample array length.
     16    */
     17   public static int toLength(double duration, int sampleRate) {
     18     return (int) Math.round(duration * sampleRate);
     19   }
     20 
     21   /**
     22    * Calculate mean of data.
     23    */
     24   public static double mean(double[] data) {
     25     Mean mean = new Mean();
     26     return mean.evaluate(data);
     27   }
     28 
     29   /**
     30    * Calculate standard deviation of data.
     31    */
     32   public static double std(double[] data) {
     33     StandardDeviation std = new StandardDeviation();
     34     return std.evaluate(data);
     35   }
     36 
     37   /**
     38    * Calculate median of data.
     39    */
     40   public static double median(double[] data) {
     41     Median median = new Median();
     42     median.setData(data);
     43     return median.evaluate();
     44   }
     45 
     46   /**
     47    * Pad zeros at the end, total length of array will be specified as length. If length is smaller
     48    * than the length of the data, it returns the data truncated to the length.
     49    */
     50   public static Complex[] padZeros(Complex[] data, int length) {
     51     Complex[] result = new Complex[length];
     52     if (length < data.length) {
     53       System.arraycopy(data, 0, result, 0, length);
     54     } else {
     55       System.arraycopy(data, 0, result, 0, data.length);
     56       for (int i = data.length; i < result.length; i++) {
     57         result[i] = new Complex(0, 0);
     58       }
     59     }
     60     return result;
     61   }
     62 
     63   /**
     64    * Calculate cross correlation using FFT with periodic boundary handling.
     65    */
     66   public static double[] computeCrossCorrelation(Complex[] data1, Complex[] data2) {
     67     FastFourierTransformer fft = new FastFourierTransformer();
     68     int n = nextPowerOfTwo(Math.max(data1.length, data2.length));
     69     Complex[] data1Fft = fft.transform(padZeros(data1, n));
     70     Complex[] data2Fft = fft.transform(padZeros(data2, n));
     71     Complex[] dottedData = new Complex[n];
     72     for (int i = 0; i < n; i++) {
     73       dottedData[i] = data1Fft[i].multiply(data2Fft[i].conjugate());
     74     }
     75     Complex[] resultComplex = fft.inversetransform(dottedData);
     76     double[] resultDouble = new double[resultComplex.length];
     77     for (int i = 0; i < resultComplex.length; i++) {
     78       resultDouble[i] = resultComplex[i].abs();
     79     }
     80     return resultDouble;
     81   }
     82 
     83   /**
     84    * Convert an short array to a double array.
     85    */
     86   public static double[] toDouble(short[] data) {
     87     double[] result = new double[data.length];
     88     for (int i = 0; i < data.length; i++) {
     89       result[i] = data[i];
     90     }
     91     return result;
     92   }
     93 
     94   /**
     95    * Convert a double array to a complex array.
     96    */
     97   public static Complex[] toComplex(double[] data) {
     98     Complex[] result = new Complex[data.length];
     99     for (int i = 0; i < data.length; i++) {
    100       result[i] = new Complex(data[i], 0.0);
    101     }
    102     return result;
    103   }
    104 
    105   /**
    106    * Calculates the next power of 2, greater than or equal to the input positive integer. If the
    107    * input is not a positive integer, it returns 1.
    108    */
    109   public static int nextPowerOfTwo(int n) {
    110     return 1 << (32 - Integer.numberOfLeadingZeros(n - 1));
    111   }
    112 
    113   /**
    114    * Find the index with the max value in an array.
    115    */
    116   public static int findMaxIndex(double[] data) {
    117     return findMaxIndex(data, 0, data.length - 1);
    118   }
    119 
    120   /**
    121    * Find the index with the max value in a sub-array.
    122    */
    123   public static int findMaxIndex(double[] data, int startIndex, int endIndex) {
    124     int maxIndex = startIndex;
    125     for (int i = startIndex + 1; i <= endIndex; i++) {
    126       if (data[i] > data[maxIndex]) {
    127         maxIndex = i;
    128       }
    129     }
    130     return maxIndex;
    131   }
    132 
    133   /**
    134    * Returns the index of an array with the array value closest to the desired value.
    135    */
    136   public static int findClosest(double[] array, double value) {
    137     double[] diffArray = new double[array.length];
    138     for (int i = 0; i < array.length; i++) {
    139       diffArray[i] = Math.abs(value - array[i]);
    140     }
    141     int index = 0;
    142     for (int i = 1; i < array.length; i++) {
    143       if (diffArray[i] < diffArray[index]) {
    144         index = i;
    145         if (diffArray[index] == 0) {
    146           break;
    147         }
    148       }
    149     }
    150     return index;
    151   }
    152 }
    153