be.tarsos.dsp.ui.layers.Scalogram Maven / Gradle / Ivy
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