All Downloads are FREE. Search and download functionalities are using the official Maven repository.

be.tarsos.dsp.pitch.GeneralizedGoertzel Maven / Gradle / Ivy

There is a newer version: 2.4-1
Show newest version
package be.tarsos.dsp.pitch;

import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.AudioProcessor;
import be.tarsos.dsp.pitch.Goertzel.FrequenciesDetectedHandler;
import be.tarsos.dsp.util.Complex;
import be.tarsos.dsp.util.fft.HammingWindow;
import be.tarsos.dsp.util.fft.WindowFunction;

/**
 * Goertzel algorithm generalized to non-integer multiples of fundamental frequency
 *  Petr Sysel and Pavel Rajmic
 * 
 * 
 * @author Joren Six
 *
 */
public class GeneralizedGoertzel implements AudioProcessor{
	
	/**
	 * A list of frequencies to detect.
	 */
	private final double[] frequenciesToDetect;
	
	private final double[] indvec;
	
	/**
	 * 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 Complex[] calculatedComplex;

	private final FrequenciesDetectedHandler handler;
	
	
	
	public GeneralizedGoertzel(final float audioSampleRate, final int bufferSize,
			double[] frequencies, FrequenciesDetectedHandler handler){
		frequenciesToDetect = frequencies;
		
		indvec = new double[frequenciesToDetect.length];
		for (int j = 0; j < frequenciesToDetect.length; j++) {
			indvec[j] = frequenciesToDetect[j]/(audioSampleRate/(float)bufferSize);
		}
		
		
		precalculatedCosines = new double[frequencies.length];
		precalculatedWnk = new double[frequencies.length];
		this.handler = handler;

		calculatedPowers = new double[frequencies.length];
		calculatedComplex = new Complex[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);
		}
		
	}
	
	@Override
	public boolean process(AudioEvent audioEvent) {
		
		float[] x = audioEvent.getFloatBuffer();
		WindowFunction f  = new HammingWindow();
		f.apply(x);
		for (int j = 0; j < frequenciesToDetect.length; j++) {
			double pik_term = 2 * Math.PI * indvec[j]/(float) audioEvent.getBufferSize(); 
			double cos_pik_term2 = Math.cos(pik_term) * 2;
			Complex cc = new Complex(0,-1*pik_term).exp();
			double s0=0;
			double s1=0;
			double s2=0;
			
			for(int i = 0 ; i < audioEvent.getBufferSize() ; i++ ){
				s0 = x[i]+cos_pik_term2*s1-s2;
				s2=s1;
				s1=s0;
			}
			s0 = cos_pik_term2 * s1 - s2;
			calculatedComplex[j] = cc.times(new Complex(-s1,0)).plus(new Complex(s0,0));
			calculatedPowers[j] = calculatedComplex[j].mod();
		}
		
		handler.handleDetectedFrequencies(audioEvent.getTimeStamp(),frequenciesToDetect.clone(), calculatedPowers.clone(),
				frequenciesToDetect.clone(), calculatedPowers.clone());
		
		return true;
	}


	@Override
	public void processingFinished() {
		
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy