package edu.cmu.sphinx.frontend.util;
import edu.cmu.sphinx.frontend.Data;
import edu.cmu.sphinx.frontend.DoubleData;
/**
* Copyright 1999-2006 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.
* <p>
* See the file "license.terms" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
* <p>
* User: Peter Wolf Date: Mar 9, 2006 Time: 9:30:52 PM
*/
public class VUMeter {
private double rms;
private double average;
private double peak;
private static final double log10 = Math.log(10.0);
private static final double maxDB = Math.max(0.0, 20.0 * Math.log(Short.MAX_VALUE) / log10);
private final int peakHoldTime = 1000;
private long then = System.currentTimeMillis();
private final float a2 = -1.9556f;
private final float a3 = 0.9565f;
private final float b1 = 0.9780f;
private final float b2 = -1.9561f;
private final float b3 = 0.9780f;
public final synchronized double getRmsDB() {
return Math.max(0.0, 20.0 * Math.log(rms) / log10);
}
public final synchronized double getAverageDB() {
return Math.max(0.0, 20.0 * Math.log(average) / log10);
}
public final synchronized double getPeakDB() {
return Math.max(0.0, 20.0 * Math.log(peak) / log10);
}
public final synchronized boolean getIsClipping() {
return (Short.MAX_VALUE) < (2 * peak);
}
public final synchronized double getMaxDB() {
return maxDB;
}
public void calculateVULevels(Data data) {
if (data instanceof DoubleData) {
double[] samples = ((DoubleData) data).getValues();
calculateVULevels(samples);
}
}
public void calculateVULevels(byte[] data, int offset, int cnt) {
short[] samples = new short[cnt / 2];
for (int i = 0; i < cnt / 2; i++) {
int o = offset + (2 * i);
samples[i] = (short) ((data[o] << 8) | (0x000000FF & data[o + 1]));
//System.out.print(data[2*i] + "+" +data[(2*i)+1] + "=" + samples[i] + " ");
}
calculateVULevels(samples);
}
private synchronized void calculateVULevels(double[] samples) {
double energy = 0.0;
average = 0.0;
double y1 = 0.0f;
double y2 = 0.0f;
for (int i = 0; i < samples.length; i++) {
// remove the DC offset with a filter
//System.out.print(samples[i] + " ");
double i1 = samples[i];
double j = 0;
double k = 0;
if (i > 0) {
j = samples[i - 1];
}
if (i > 1) {
k = samples[i - 2];
}
double y = b1 * i1 + b2 * j + b3 * k - a2 * y1 - a3 * y2;
y2 = y1;
y1 = y;
double v2 = Math.abs(y);
long now = System.currentTimeMillis();
energy += v2 * v2;
average += v2;
if (v2 > peak) {
peak = v2;
} else if ((now - then) > peakHoldTime) {
peak = v2;
then = now;
}
}
rms = energy / samples.length;
rms = Math.sqrt(rms);
average /= samples.length;
}
private synchronized void calculateVULevels(short[] samples) {
double energy = 0.0;
average = 0.0;
double y1 = 0.0f;
double y2 = 0.0f;
for (int i = 0; i < samples.length; i++) {
// remove the DC offset with a filter
//System.out.print(samples[i] + " ");
short i1 = samples[i];
double j = 0;
double k = 0;
if (i > 0) {
j = samples[i - 1];
}
if (i > 1) {
k = samples[i - 2];
}
double y = b1 * i1 + b2 * j + b3 * k - a2 * y1 - a3 * y2;
y2 = y1;
y1 = y;
double v2 = Math.abs(y);
long now = System.currentTimeMillis();
energy += v2 * v2;
average += v2;
if (v2 > peak) {
peak = v2;
} else if ((now - then) > peakHoldTime) {
peak = v2;
then = now;
}
}
rms = energy / samples.length;
rms = Math.sqrt(rms);
average /= samples.length;
}
}