/*
* Copyright 1999-2013 Carnegie Mellon University.
* 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.tools.bandwidth;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import edu.cmu.sphinx.frontend.*;
import edu.cmu.sphinx.frontend.frequencywarp.MelFrequencyFilterBank;
import edu.cmu.sphinx.frontend.transform.DiscreteFourierTransform;
import edu.cmu.sphinx.frontend.util.AudioFileDataSource;
import edu.cmu.sphinx.frontend.window.RaisedCosineWindower;
/**
* A simple energy-based detector for upsampled audio. Could be used to detect
* bandwidth issues leading to the accuracy issues.
*
* The detector simply looks for energies in different mel bands and using the
* threshold it decides if we have cut of the frequencies signal. On every frame
* we find the maximum energy band, then we just control that energy doesn't
* fall too fast in upper bands.
*
* A paper on the subject is "DETECTING BANDLIMITED AUDIO IN BROADCAST TELEVISION SHOWS"
* by by Mark C. Fuhs, Qin Jin and Tanja Schultz where spline approximation is proposed
* for detection. However, the paper seems to contain a fundamental flaw. The
* decision is made on average spectrum, not per-frame. This probably leads
* to omission of the events in high frequency which might signal about wide band.
*/
public class BandDetector {
static final int bands = 40;
// From 4750 to 6800 Hz
static final int highRangeStart = 35;
static final int highRangeEnd = 39;
// From 2156 to 3687 Hz
static final int lowRangeStart = 23;
static final int lowRangeEnd = 29;
// Thresholds, selected during the experiments, about -30dB
static final double noSignalLevel = 0.02;
static final double signalLevel = 0.5;
// Don't care if intensity is very low
static final double lowIntensity = 1e+5;
private FrontEnd frontend;
private AudioFileDataSource source;
public BandDetector() {
// standard frontend
source = new AudioFileDataSource(320, null);
RaisedCosineWindower windower = new RaisedCosineWindower(0.97f,
25.625f, 10.0f);
DiscreteFourierTransform fft = new DiscreteFourierTransform(512, false);
MelFrequencyFilterBank filterbank = new MelFrequencyFilterBank(130.0,
6800.0, bands);
ArrayList<DataProcessor> list = new ArrayList<DataProcessor>();
list.add(source);
list.add(windower);
list.add(fft);
list.add(filterbank);
frontend = new FrontEnd(list);
}
public static void main(String args[]) throws FileNotFoundException {
if (args.length < 1) {
System.out
.println("Usage: Detector <filename.wav> or Detector <filelist>");
return;
}
if (args[0].endsWith(".wav")) {
BandDetector detector = new BandDetector();
System.out.println("Bandwidth for " + args[0] + " is "
+ detector.bandwidth(args[0]));
} else {
BandDetector detector = new BandDetector();
Scanner s = new Scanner(new File(args[0]));
while (s.hasNextLine()) {
String line = s.nextLine().trim();
if (detector.bandwidth(line))
System.out.println("Bandwidth for " + line + " is low");
}
s.close();
}
return;
}
public boolean bandwidth(String file) {
source.setAudioFile(new File(file), "");
Data data;
double energy[] = new double[bands];
while ((data = frontend.getData()) != null) {
if (data instanceof DoubleData) {
double maxIntensity = lowIntensity;
double[] frame = ((DoubleData) data).getValues();
for (int i = 0; i < bands; i++)
maxIntensity = Math.max(maxIntensity, frame[i]);
if (maxIntensity <= lowIntensity) {
continue;
}
for (int i = 0; i < bands; i++) {
energy[i] = Math.max(frame[i] / maxIntensity, energy[i]);
}
}
}
double maxLow = max(energy, lowRangeStart, lowRangeEnd);
double maxHi = max(energy, highRangeStart, highRangeEnd);
// System.out.format("%f %f\n", maxHi, maxLow);
// for (int i = 0; i < bands; i++)
// System.out.format("%.4f ", energy[i]);
// System.out.println();
if (maxHi < noSignalLevel && maxLow > signalLevel)
return true;
return false;
}
private double max(double[] energy, int start, int end) {
double max = 0;
for (int i = start; i <= end; i++)
max = Math.max(max, energy[i]);
return max;
}
}