package org.vocvark.AudioFeatures;
import org.vocvark.DataTypes.FeatureDefinition;
/**
* Class that calculates the first 5 stastical method of moments (Fujinaga
* 1997). Very similar to Area Method of Moments feature, but does not have the
* large offset - this feature starts producing results on the first window.
* <p/>
* Fujinaga, I. <i>Adaptive Optical Music Recognition</i>. PhD thesis, McGill
* University, 1997.
*
* @author Daniel McEnnis
*/
public class Moments extends FeatureExtractorBaseImpl {
/**
* Base constructor that defines definition, dependencies, and offsets.
*/
public Moments() {
String name = "Method of Moments";
String description = "Statistical Method of Moments of the Magnitude Spectrum.";
definition = new FeatureDefinition(name, description, true, 5);
dependencies = new String[]{"Magnitude Spectrum"};
offsets = new int[]{0};
}
/**
* Calculates method of moments on the magnitude spectrum.
*
* @param samples The samples to extract the feature from.
* @param sampling_rate The sampling rate that the samples are encoded with.
* @param other_feature_values The values of other features that are needed to calculate this
* value. The order and offsets of these features must be the
* same as those returned by this class's getDependencies and
* getDependencyOffsets methods respectively. The first indice
* indicates the feature/window and the second indicates the
* value.
* @return The extracted feature value(s).
* @throws Exception Throws an informative exception if the feature cannot be
* calculated.
*/
public double[] extractFeature(double[] samples, double sampling_rate,
double[][] other_feature_values) throws Exception {
double ret[] = new double[5];
double[] mom = new double[5];
double scale = 0;
double tmp = 0.0;
// first get the total area
for (int i = 0; i < other_feature_values[0].length; ++i) {
scale += other_feature_values[0][i];
}
// if the signal is complete silence, output zero
if (scale == 0.0) {
return new double[]{0.0, 0.0, 0.0, 0.0, 0.0};
}
// calculate each value using the mean to scale 'area' to a sum of 1
for (int i = 0; i < other_feature_values[0].length; ++i) {
tmp = other_feature_values[0][i] / scale;
for (int j = 1; j < ret.length; ++j) {
mom[j] += (tmp *= i);
}
}
ret[0] = scale; // total 'area'
ret[1] = mom[1]; // mean
ret[2] = mom[2] - mom[1] * mom[1]; // spectral centroid
ret[3] = 2 * Math.pow(mom[1], 3.0) - 3 * mom[1] * mom[2] + mom[3]; // skewness
ret[4] = -3 * Math.pow(mom[1], 4.0) + 6 * mom[1] * mom[1] * mom[2] - 4
* mom[1] * mom[3] + mom[4];// kurtosis
return ret;
}
/**
* Create an identical copy of this feature. This permits FeatureExtractor
* to use the prototype pattern to create new composite features using
* metafeatures.
*/
public Object clone() {
return new Moments();
}
}