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

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

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

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.Map;
import java.util.TreeMap;

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.AudioProcessor;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.ui.Axis;
import be.tarsos.dsp.ui.CoordinateSystem;
import be.tarsos.dsp.ui.layers.TooltipLayer.TooltipTextGenerator;
import be.tarsos.dsp.util.PitchConverter;
import be.tarsos.dsp.wavelet.HaarWaveletTransform;
import be.tarsos.dsp.wavelet.lift.Daubechies4Wavelet;

public class Scalogram implements Layer, Runnable, TooltipTextGenerator {
	
	private final String audioFile;
	private TreeMap features;
	private final CoordinateSystem cs;  
	public Scalogram(CoordinateSystem cs, String audioFile){
		this.audioFile = audioFile;
		this.cs = cs;
		features = null;
		new Thread(this,"Extract Scalogram").start();
	}	

	@Override
	public void draw(Graphics2D graphics) {
		if(features==null){
		return ;
		}
		Map spectralInfoSubMap = features.subMap(cs.getMin(Axis.X) / 1000.0, cs.getMax(Axis.X) / 1000.0);
		for (Map.Entry frameEntry : spectralInfoSubMap.entrySet()) {
				double timeStart = frameEntry.getKey();// in seconds
				ScalogramFrame frame = frameEntry.getValue();// in cents
				
				
				for (int level = 0; level < frame.dataPerScale.length; level++) {
					for(int block = 0; block < frame.dataPerScale[level].length ; block++){
						Color color = Color.black;
						float centsStartingPoint = frame.startFrequencyPerLevel[level];
						float centsHeight = frame.stopFrequencyPerLevel[level] - centsStartingPoint;
						// only draw the visible frequency range
						if (centsStartingPoint + centsHeight >= cs.getMin(Axis.Y) && centsStartingPoint <= cs.getMax(Axis.Y)) {
							float factor = Math.abs(frame.dataPerScale[level][block] / frame.currentMax);
							
							double startTimeBlock = timeStart + (block+1) * frame.durationsOfBlockPerLevel[level];
							double timeDuration = frame.durationsOfBlockPerLevel[level];
							
							int greyValue = (int) ( factor* 0.99 * 255);
							greyValue = Math.max(0, greyValue);
							color = new Color(greyValue, greyValue, greyValue);
							graphics.setColor(color);
							graphics.fillRect((int) Math.round(startTimeBlock * 1000),
									Math.round(centsStartingPoint),
									(int) Math.round(timeDuration * 1000),
									(int) Math.ceil(centsHeight));
						}
					}
				}
		}
				
	}

	@Override
	public String getName() {
		return "Scalogram";
	}



	@Override
	public void run() {
		AudioDispatcher adp = AudioDispatcherFactory.fromPipe(audioFile, 44100, 131072, 0);
		adp.addAudioProcessor(new AudioProcessor() {
			
			Daubechies4Wavelet wt = new Daubechies4Wavelet();
			TreeMap calculatigFeatures = new TreeMap();
			ScalogramFrame prevFrame;
			@Override
			public boolean process(AudioEvent audioEvent) {
			float[] audioBuffer = audioEvent.getFloatBuffer().clone();
				wt.forwardTrans(audioBuffer);
				float currentMax = 0;
				if(prevFrame != null){
					currentMax = prevFrame.currentMax * 0.99f;
				}
				ScalogramFrame currentFrame = new ScalogramFrame(audioBuffer,currentMax);
				calculatigFeatures.put(audioEvent.getTimeStamp(),currentFrame);
				prevFrame = currentFrame;
				return true;
			}
			
			@Override
			public void processingFinished() {
				features = calculatigFeatures;
			}
		});
		adp.run();
	}
	
	private static class ScalogramFrame{
		float[][] dataPerScale;
		float[] durationsOfBlockPerLevel;
		float[] startFrequencyPerLevel;//cents
		float[] stopFrequencyPerLevel;//cents
		
		float currentMax;
		
		public ScalogramFrame(float[] transformedData, float currentMax){
			this.currentMax = currentMax;
			int levels = HaarWaveletTransform.log2(transformedData.length);
			dataPerScale = new float[levels][];
			durationsOfBlockPerLevel = new float[levels];
			startFrequencyPerLevel = new float[levels];
			stopFrequencyPerLevel = new float[levels];
			for(int i = 0 ; i 0){
					startFrequencyPerLevel[i] = stopFrequencyPerLevel[i-1];
				}
				mra(transformedData,i,dataPerScale);
			}
			
		}
		
		private void mra(float[] transformedData,int level,float[][] dataPerScale){
			int startIndex = (int) (transformedData.length/HaarWaveletTransform.pow2(dataPerScale.length - level));
			int stopIndex = (int) (transformedData.length/HaarWaveletTransform.pow2(dataPerScale.length - level-1));
		
			int j = 0;
			for(int i = startIndex ; i < stopIndex ;i++){
				dataPerScale[level][j] = -1 * transformedData[i];
				j++;
			}
			normalize(dataPerScale[level]);
		}
		
		private void normalize(float[] data){
			for(int i = 0 ; i < data.length ;i++){
				currentMax = Math.max(Math.abs(data[i]),currentMax);
			}
			for(int i = 0 ; i < data.length ;i++){
				//data[i]=data[i]/maxValue;
			}
		}
		
	}

	@Override
	public String generateTooltip(CoordinateSystem cs, Point2D point) {
		return "Scale info";
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy