be.tarsos.dsp.pitch.Goertzel Maven / Gradle / Ivy
/*
* _______ _____ _____ _____
* |__ __| | __ \ / ____| __ \
* | | __ _ _ __ ___ ___ ___| | | | (___ | |__) |
* | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/
* | | (_| | | \__ \ (_) \__ \ |__| |____) | |
* |_|\__,_|_| |___/\___/|___/_____/|_____/|_|
*
* -------------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at IPEM, University Ghent
*
* -------------------------------------------------------------
*
* Info: http://0110.be/tag/TarsosDSP
* Github: https://github.com/JorenSix/TarsosDSP
* Releases: http://0110.be/releases/TarsosDSP/
*
* TarsosDSP includes modified source code by various authors,
* for credits and info, see README.
*
*/
package be.tarsos.dsp.pitch;
import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.AudioProcessor;
/**
* Contains an implementation of the Goertzel algorithm. It can be used to
* detect if one or more predefined frequencies are present in a signal. E.g. to
* do DTMF decoding.
*
* @author Joren Six
*/
public class Goertzel implements AudioProcessor {
/**
* If the power in dB is higher than this threshold, the frequency is
* present in the signal.
*/
private static final double POWER_THRESHOLD = 35;// in dB
/**
* A list of frequencies to detect.
*/
private final double[] frequenciesToDetect;
/**
* Cached cosine calculations for each frequency to detect.
*/
private final double[] precalculatedCosines;
/**
* Cached wnk calculations for each frequency to detect.
*/
private final double[] precalculatedWnk;
/**
* A calculated power for each frequency to detect. This array is reused for
* performance reasons.
*/
private final double[] calculatedPowers;
private final FrequenciesDetectedHandler handler;
public Goertzel(final float audioSampleRate, final int bufferSize,
double[] frequencies, FrequenciesDetectedHandler handler) {
frequenciesToDetect = frequencies;
precalculatedCosines = new double[frequencies.length];
precalculatedWnk = new double[frequencies.length];
this.handler = handler;
calculatedPowers = new double[frequencies.length];
for (int i = 0; i < frequenciesToDetect.length; i++) {
precalculatedCosines[i] = 2 * Math.cos(2 * Math.PI
* frequenciesToDetect[i] / audioSampleRate);
precalculatedWnk[i] = Math.exp(-2 * Math.PI
* frequenciesToDetect[i] / audioSampleRate);
}
}
/**
* An interface used to react on detected frequencies.
*
* @author Joren Six
*/
public static interface FrequenciesDetectedHandler {
/**
* React on detected frequencies.
*
* @param frequencies
* A list of detected frequencies.
* @param powers
* A list of powers of the detected frequencies.
* @param allFrequencies
* A list of all frequencies that were checked.
* @param allPowers
* A list of powers of all frequencies that were checked.
*/
void handleDetectedFrequencies(final double timestamp,final double[] frequencies,
final double[] powers, final double[] allFrequencies,
final double allPowers[]);
}
@Override
public boolean process(AudioEvent audioEvent) {
float[] audioFloatBuffer = audioEvent.getFloatBuffer();
double skn0, skn1, skn2;
int numberOfDetectedFrequencies = 0;
for (int j = 0; j < frequenciesToDetect.length; j++) {
skn0 = skn1 = skn2 = 0;
for (int i = 0; i < audioFloatBuffer.length; i++) {
skn2 = skn1;
skn1 = skn0;
skn0 = precalculatedCosines[j] * skn1 - skn2
+ audioFloatBuffer[i];
}
double wnk = precalculatedWnk[j];
calculatedPowers[j] = 20 * Math.log10(Math.abs(skn0 - wnk * skn1));
if (calculatedPowers[j] > POWER_THRESHOLD) {
numberOfDetectedFrequencies++;
}
}
if (numberOfDetectedFrequencies > 0) {
double[] frequencies = new double[numberOfDetectedFrequencies];
double[] powers = new double[numberOfDetectedFrequencies];
int index = 0;
for (int j = 0; j < frequenciesToDetect.length; j++) {
if (calculatedPowers[j] > POWER_THRESHOLD) {
frequencies[index] = frequenciesToDetect[j];
powers[index] = calculatedPowers[j];
index++;
}
}
handler.handleDetectedFrequencies(audioEvent.getTimeStamp(),frequencies, powers,
frequenciesToDetect.clone(), calculatedPowers.clone());
}
return true;
}
@Override
public void processingFinished() {
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy