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    */
toLength(double duration, int sampleRate)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    */
mean(double[] data)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    */
std(double[] data)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    */
median(double[] data)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    */
padZeros(Complex[] data, int length)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    */
computeCrossCorrelation(Complex[] data1, Complex[] data2)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    */
toDouble(short[] data)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    */
toComplex(double[] data)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    */
nextPowerOfTwo(int n)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    */
findMaxIndex(double[] data)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    */
findMaxIndex(double[] data, int startIndex, int endIndex)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    */
findClosest(double[] array, double value)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