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

be.tarsos.dsp.ui.layers.GeneralizedGoertzelLayer Maven / Gradle / Ivy

There is a newer version: 2.4-1
Show newest version
/*
*      _______                       _____   _____ _____  
*     |__   __|                     |  __ \ / ____|  __ \ 
*        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
*        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
*        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
*        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
*                                                         
* -------------------------------------------------------------
*
* 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.ui.layers;

import java.awt.Color;
import java.awt.Graphics2D;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;

import javax.sound.sampled.UnsupportedAudioFileException;

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.StopAudioProcessor;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.pitch.GeneralizedGoertzel;
import be.tarsos.dsp.pitch.Goertzel.FrequenciesDetectedHandler;
import be.tarsos.dsp.ui.Axis;
import be.tarsos.dsp.ui.CoordinateSystem;
import be.tarsos.dsp.util.PitchConverter;



public class GeneralizedGoertzelLayer implements Layer{

	private TreeMap features;
	private final CoordinateSystem cs;
	private final File audioFile;
	

	private double maxSpectralEnergy = 0;
	private double minSpectralEnergy = 100000;
	private float[] binStartingPointsInCents;
	private float binWith;// in seconds
	private float binHeight;// in cents

	

	public GeneralizedGoertzelLayer(CoordinateSystem cs, File audioFile, int binHeightInCents) {
		this.cs = cs;		
		this.audioFile = audioFile;
	}

	public void draw(Graphics2D graphics) {
		
		calculateFeatures();
		
		if(features != null){
			Map spectralInfoSubMap = features.subMap(
					cs.getMin(Axis.X) / 1000.0, cs.getMax(Axis.X) / 1000.0);
			for (Map.Entry column : spectralInfoSubMap.entrySet()) {
				double timeStart = column.getKey();// in seconds
				double[] spectralEnergy = column.getValue();// in cents
	
				// draw the pixels
				for (int i = 0; i < spectralEnergy.length; i++) {
					Color color = Color.black;
					float centsStartingPoint = binStartingPointsInCents[i];
					// only draw the visible frequency range
					if (centsStartingPoint >= cs.getMin(Axis.Y)
							&& centsStartingPoint <= cs.getMax(Axis.Y)) {
						
						double factor = spectralEnergy[i] / maxSpectralEnergy;
						int greyValue = 255 - (int) (factor * 255) ;
						greyValue = Math.max(0, greyValue);
						color = new Color(greyValue, greyValue, greyValue);
						graphics.setColor(color);
						graphics.fillRect((int) Math.round(timeStart * 1000),
								Math.round(centsStartingPoint),
								(int) Math.round(binWith * 1000),
								(int) Math.ceil(binHeight));
					}
				}
			}
		}
	}
	
	

	
	public void calculateFeatures() {
		try {
			//maxSpectralEnergy = 0;
			//minSpectralEnergy = 100000;
			int blockSize = 8000;
			int overlap = 7500;
			AudioDispatcher adp =  AudioDispatcherFactory.fromFile(audioFile, blockSize,overlap);
			adp.skip(Math.max(0, cs.getMin(Axis.X)/1000.0));
			adp.addAudioProcessor(new StopAudioProcessor(cs.getMax(Axis.X)/1000.0));
			
			final float sampleRate = adp.getFormat().getFrameRate();
			
			double lowFrequencyInCents = cs.getMin(Axis.Y);
			double highFrequencyInCents = cs.getMax(Axis.Y);
			
			int steps = 50; // 100 steps;
			double stepInCents = (highFrequencyInCents - lowFrequencyInCents) / (float) steps;
			

			binWith = (blockSize - overlap)	/  sampleRate;
			binHeight = (float) stepInCents;
			double[] frequencies = new double[steps];
			binStartingPointsInCents = new float[steps];
			for(int i = 0 ; i< steps ; i++){
				double valueInCents = i * stepInCents + lowFrequencyInCents;
				frequencies[i] = PitchConverter.absoluteCentToHertz(valueInCents);
				binStartingPointsInCents[i]=(float)valueInCents;
			}
			
			final TreeMap fe = new TreeMap();
			
			FrequenciesDetectedHandler handler= new FrequenciesDetectedHandler(){
				int i = 0;
				@Override
				public void handleDetectedFrequencies(double time, double[] frequencies,
						double[] powers, double[] allFrequencies,
						double[] allPowers) {
						
						double timeStamp = (Math.max(0, cs.getMin(Axis.X)/1000.0)) + i * binWith;
						i++;
						fe.put(timeStamp,allPowers.clone());
				}};
				
			final GeneralizedGoertzel goertzel = new GeneralizedGoertzel(sampleRate,blockSize,frequencies,handler);
			adp.addAudioProcessor(goertzel);
			adp.run();
			
			for (double[] magnitudes : fe.values()) {
				for (int i = 0; i < magnitudes.length; i++) {
					if(magnitudes[i]==0){
						magnitudes[i] = 1.0/(float)1e10;
					}
					//to dB
					magnitudes[i] = 20 * Math.log(1+Math.abs(magnitudes[i]))/Math.log(10);
					
					maxSpectralEnergy = Math.max(magnitudes[i],maxSpectralEnergy);
					minSpectralEnergy = Math.min(magnitudes[i],minSpectralEnergy);
				}
			}
			minSpectralEnergy = Math.abs(minSpectralEnergy);
			this.features = fe;
			
		} catch (UnsupportedAudioFileException e) {
			e.printStackTrace();
		} catch (IOException e2){
			e2.printStackTrace();
		}
		
		
	}

	@Override
	public String getName() {
		return "Generalized Goertzel Layer";
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy