/*
* Copyright 1999-2002 Carnegie Mellon University.
* Portions Copyright 2002 Sun * Microsystems, Inc.
* Portions Copyright 2002 Mitsubishi Electric Research Laboratories.
*
* All Rights Reserved. Use is subject to license terms.
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*/
package edu.cmu.sphinx.frontend.frequencywarp;
import static java.util.Arrays.copyOfRange;
/**
* Defines a triangular mel-filter.
*
* The {@link MelFrequencyFilterBank2} creates mel-filters and filters spectrum.
*
* A mel-filter is a triangular shaped bandpass filter. When a mel-filter is
* constructed, the parameters <code>leftEdge</code>, <code>rightEdge</code>,
* <code>centerFreq</code>, <code>initialFreq</code>, and
* <code>deltaFreq</code> are given to the {@link MelFilter2 Constructor}. The
* first three arguments to the constructor, i.e. <code>leftEdge</code>,
* <code>rightEdge</code>, and <code>centerFreq</code>, specify the filter's
* slopes. The total area under the filter is 1. The filter is shaped as a
* triangle. Knowing the distance between the center frequency and each of the
* edges, it is easy to compute the slopes of the two sides in the triangle -
* the third side being the frequency axis. The last two arguments,
* <code>initialFreq</code> and <code>deltaFreq</code>, identify the first
* frequency bin that falls inside this filter and the spacing between
* successive frequency bins. All frequencies here are considered in a linear
* scale.
*
* Figure 1 below shows pictorially what the other parameters mean.
*
* <img alt="Mel filter" src="doc-files/melfilter.jpg"> <br>
* <center><b>Figure 1: A triangular mel-filter.</b></center>
*
* @see MelFrequencyFilterBank2
*/
public class MelFilter2 {
private final int offset;
private final double[] weights;
public MelFilter2(double center, double delta, double[] melPoints) {
int lastIndex = 0;
int firstIndex = melPoints.length;
double left = center - delta;
double right = center + delta;
double [] heights = new double[melPoints.length];
for (int i = 0; i < heights.length; ++i) {
if (left < melPoints[i] && melPoints[i] <= center) {
heights[i] = (melPoints[i] - left) / (center - left);
firstIndex = Math.min(i, firstIndex);
lastIndex = i;
}
if (center < melPoints[i] && melPoints[i] < right) {
heights[i] = (right - melPoints[i]) / (right - center);
lastIndex = i;
}
}
offset = firstIndex;
weights = copyOfRange(heights, firstIndex, lastIndex + 1);
}
public double apply(double[] powerSpectrum) {
double result = 0;
for (int i = 0; i < weights.length; ++i)
result += weights[i] * powerSpectrum[offset + i];
return result;
}
}