/*
* @(#)SpectralRolloffPoint.java 1.0 April 5, 2005.
*
* McGill Univarsity
*/
package org.vocvark.AudioFeatures;
import org.vocvark.DataTypes.FeatureDefinition;
/**
* A feature extractor that extracts the Spectral Rolloff Point. This is a
* measure measure of the amount of the right-skewedness of the power spectrum.
* <p/>
* The spectral rolloff point is the fraction of bins in the power spectrum at
* which 85% of the power is at lower frequencies.
* <p/>
* No extracted feature values are stored in objects of this class.
*
* @author Cory McKay
*/
public class SpectralRolloffPoint extends FeatureExtractorBaseImpl {
protected double cutoff = 0.85;
/* CONSTRUCTOR ************************************************************* */
/**
* Basic constructor that sets the definition and dependencies (and their
* offsets) of this feature.
*/
public SpectralRolloffPoint() {
String name = "Spectral Rolloff Point";
String description = "The fraction of bins in the power spectrum at which 85% "
+ // System.getProperty("line.separator") +
"of the power is at lower frequencies. This is a measure " + // System.getProperty("line.separator")
// +
"of the right-skewedness of the power spectrum.";
boolean is_sequential = true;
int dimensions = 1;
definition = new FeatureDefinition(name, description, is_sequential,
dimensions, new String[]{"Cutoff point (0-1)"});
dependencies = new String[1];
dependencies[0] = "Power Spectrum";
offsets = new int[1];
offsets[0] = 0;
}
/* PUBLIC METHODS ********************************************************* */
/**
* Extracts this feature from the given samples at the given sampling rate
* and given the other feature values.
* <p/>
* In the case of this feature, the sampling_rate parameter is ignored.
*
* @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[] pow_spectrum = other_feature_values[0];
double total = 0.0;
for (int bin = 0; bin < pow_spectrum.length; bin++)
total += pow_spectrum[bin];
double threshold = total * cutoff;
total = 0.0;
int point = 0;
for (int bin = 0; bin < pow_spectrum.length; bin++) {
total += pow_spectrum[bin];
if (total >= threshold) {
point = bin;
bin = pow_spectrum.length;
}
}
double[] result = new double[1];
result[0] = ((double) point) / ((double) pow_spectrum.length);
return result;
}
/**
* 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() {
SpectralRolloffPoint ret = new SpectralRolloffPoint();
ret.cutoff = cutoff;
return ret;
}
/**
* Function permitting an unintelligent outside function (ie. EditFeatures
* frame) to get the default values used to populate the table's entries.
* The correct index values are inferred from definition.attribute value.
*
* @param index which of AreaMoment's attributes should be edited.
*/
public String getElement(int index) throws Exception {
if (index != 0) {
throw new Exception("INTERNAL ERROR: invalid index " + index
+ " sent to AreaMoments:getElement");
} else {
return Double.toString(cutoff);
}
}
/**
* Function permitting an unintelligent outside function (ie. EditFeatures
* frame) to set the default values used to popylate the table's entries.
* Like getElement, the correct index values are inferred from the
* definition.attributes value.
*
* @param index attribute to be set
* @param value new value of the attribute
*/
public void setElement(int index, String value) throws Exception {
if (index != 0) {
throw new Exception("INTERNAL ERROR: invalid index " + index
+ " sent to AreaMoments:setElement");
} else {
try {
double type = Double.parseDouble(value);
setCutoff(type);
} catch (Exception e) {
throw new Exception(
"Length of Area Method of Moments must be an integer");
}
}
}
/**
* Permits users to set the rpecise cutoff point. THis value should be
* strictly between 0 and 1.
*
* @param c new cutoff point
* @throws Exception thrown if c is not a real number strictly between 0 and 1.
*/
public void setCutoff(double c) throws Exception {
if (Double.isInfinite(c) || Double.isNaN(c)) {
throw new Exception("SpectralRolloff cutoff must be a real number");
} else if ((c <= 0.0) || (c >= 1.0)) {
throw new Exception(
"SpectralRolloff cutoff must be gretaer than 0 and less than 1");
} else {
cutoff = c;
}
}
}