blob: 4ef62d93252deed2b2e1f3f0930880b1d4196c74 [file] [log] [blame]
package com.android.cts.verifier.audio;
import org.apache.commons.math.complex.Complex;
import org.apache.commons.math.stat.descriptive.moment.Mean;
import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
import org.apache.commons.math.stat.descriptive.rank.Median;
import org.apache.commons.math.transform.FastFourierTransformer;
/**
* This class contains util functions used in the WavAnalyzer.
*/
public class Util {
/**
* Convert time in second to sample array length.
*/
public static int toLength(double duration, int sampleRate) {
return (int) Math.round(duration * sampleRate);
}
/**
* Calculate mean of data.
*/
public static double mean(double[] data) {
Mean mean = new Mean();
return mean.evaluate(data);
}
/**
* Calculate standard deviation of data.
*/
public static double std(double[] data) {
StandardDeviation std = new StandardDeviation();
return std.evaluate(data);
}
/**
* Calculate median of data.
*/
public static double median(double[] data) {
Median median = new Median();
median.setData(data);
return median.evaluate();
}
/**
* Pad zeros at the end, total length of array will be specified as length. If length is smaller
* than the length of the data, it returns the data truncated to the length.
*/
public static Complex[] padZeros(Complex[] data, int length) {
Complex[] result = new Complex[length];
if (length < data.length) {
System.arraycopy(data, 0, result, 0, length);
} else {
System.arraycopy(data, 0, result, 0, data.length);
for (int i = data.length; i < result.length; i++) {
result[i] = new Complex(0, 0);
}
}
return result;
}
/**
* Calculate cross correlation using FFT with periodic boundary handling.
*/
public static double[] computeCrossCorrelation(Complex[] data1, Complex[] data2) {
FastFourierTransformer fft = new FastFourierTransformer();
int n = nextPowerOfTwo(Math.max(data1.length, data2.length));
Complex[] data1Fft = fft.transform(padZeros(data1, n));
Complex[] data2Fft = fft.transform(padZeros(data2, n));
Complex[] dottedData = new Complex[n];
for (int i = 0; i < n; i++) {
dottedData[i] = data1Fft[i].multiply(data2Fft[i].conjugate());
}
Complex[] resultComplex = fft.inversetransform(dottedData);
double[] resultDouble = new double[resultComplex.length];
for (int i = 0; i < resultComplex.length; i++) {
resultDouble[i] = resultComplex[i].abs();
}
return resultDouble;
}
/**
* Convert an short array to a double array.
*/
public static double[] toDouble(short[] data) {
double[] result = new double[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = data[i];
}
return result;
}
/**
* Convert a double array to a complex array.
*/
public static Complex[] toComplex(double[] data) {
Complex[] result = new Complex[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = new Complex(data[i], 0.0);
}
return result;
}
/**
* Calculates the next power of 2, greater than or equal to the input positive integer. If the
* input is not a positive integer, it returns 1.
*/
public static int nextPowerOfTwo(int n) {
return 1 << (32 - Integer.numberOfLeadingZeros(n - 1));
}
/**
* Find the index with the max value in an array.
*/
public static int findMaxIndex(double[] data) {
return findMaxIndex(data, 0, data.length - 1);
}
/**
* Find the index with the max value in a sub-array.
*/
public static int findMaxIndex(double[] data, int startIndex, int endIndex) {
int maxIndex = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++) {
if (data[i] > data[maxIndex]) {
maxIndex = i;
}
}
return maxIndex;
}
/**
* Returns the index of an array with the array value closest to the desired value.
*/
public static int findClosest(double[] array, double value) {
double[] diffArray = new double[array.length];
for (int i = 0; i < array.length; i++) {
diffArray[i] = Math.abs(value - array[i]);
}
int index = 0;
for (int i = 1; i < array.length; i++) {
if (diffArray[i] < diffArray[index]) {
index = i;
if (diffArray[index] == 0) {
break;
}
}
}
return index;
}
}