import java.awt.*;
import jass.engine.*;
import jass.generators.*;
import jass.render.*;
import jass.patches.*;
/**
Grab a line segment based on current and previous mouse position and make sound based on that
@author Kees van den Doel (kvdoel@cs.ubc.ca)
*/
public class GrabSegmentScrape extends Out {
private SegmentDataProvider segmentDataProvider;
private float[] hsb = new float[3];
private float[] tmprgb = new float[3];
private float[] rgb = new float[3];
private float[] lch = new float[3];
protected float srate;
private String syfile;
private String wavfile;
private LowpassColorSonificator colorSonificator;
private ModalModel resonantSurfaceModes;
private ModalObjectWithOneContact resonantSurface;
private boolean haveSy = true; // use sy file or not
private RandOut excitation;
private Butter2LowFilter butterFilterX; // filter mouseX
private Butter2LowFilter butterFilterY; // filter mouseY
private float mouseSamplingRate;
private float cutOffFreqMouse=1; // determines smoothness/latency
private float pixelsPerMeter;
private float unitScrapeVelocity = .01f; // in m/s, can be 2.5 as fast
public GrabSegmentScrape(int bufferSize, float srate, SegmentDataProvider sdp,String syfile,float pixelsPerCm) {
super(bufferSize);
this.pixelsPerMeter = 100*pixelsPerCm;
this.segmentDataProvider = sdp;
this.srate = srate;
this.syfile=syfile;
createPatch();
}
/** Set center speed in m/s, can be up to twice as fast
@param v center speed
*/
public void setUnitScrapeVelocity(float v) {
unitScrapeVelocity = v;
}
/** Get center speed in m/s, can be up to twice as fast
@return center speed
*/
public float getUnitScrapeVelocity() {
return unitScrapeVelocity;
}
/**
Set lowpass mouse motion freq. cutoff
@param f lowpass cutoff for mouse in Hetrz
*/
public void setLowPassMouseMotionFilterFrequencyCutoff(float f) {
cutOffFreqMouse = f;
butterFilterX.setCutoffFrequency(cutOffFreqMouse);
butterFilterY.setCutoffFrequency(cutOffFreqMouse);
}
/**
Get lowpass mouse motion freq. cutoff
@return lowpass cutoff for mouse in Hetrz
*/
public float getLowPassMouseMotionFilterFrequencyCutoff() {
return cutOffFreqMouse;
}
private void createPatch() {
colorSonificator = new LowpassColorSonificator(srate,bufferSize);
excitation = new RandOut(bufferSize);
mouseSamplingRate = srate/getBufferSize();
try {
resonantSurfaceModes = new ModalModel(syfile);
haveSy = true;
} catch(Exception e) {
haveSy = false;
// System.out.println("Can't load sy file "+e);
}
if(haveSy) {
resonantSurface = new ModalObjectWithOneContact(resonantSurfaceModes,srate,bufferSize);
}
try {
colorSonificator.addSource(excitation);
if(haveSy) {
resonantSurface.addSource(colorSonificator);
}
} catch(Exception e) {
}
butterFilterX = new Butter2LowFilter((float)mouseSamplingRate);
butterFilterX.setCutoffFrequency(cutOffFreqMouse);
butterFilterY = new Butter2LowFilter((float)mouseSamplingRate);
butterFilterY.setCutoffFrequency(cutOffFreqMouse);
}
private float[] pixel2hsb(int pixel) {
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;
java.awt.Color.RGBtoHSB(red,green,blue,hsb);
return hsb;
}
private float[] pixel2rgb(int pixel) {
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;
tmprgb[0] = red;
tmprgb[1] = green;
tmprgb[2] = blue;
return tmprgb;
}
private int[] mousepos = new int[2];
private Dimension imageDimension;
private int bufsz;
private int[] imagePixels;
private int current_pixel;
private float[] mouseX = new float[2];
private float[] mouseY = new float[2];
private int mouseQueueSize = 2;
protected void computeBuffer() {
bufsz = getBufferSize();
mousepos = segmentDataProvider.getMousePosition();
mouseX[0] = mouseX[1];
mouseY[0] = mouseY[1];
mouseX[1] = mousepos[0]/pixelsPerMeter;
mouseY[1] = mousepos[1]/pixelsPerMeter;
int offset = 0;
butterFilterX.filter(mouseX,mouseX,mouseQueueSize,offset);
butterFilterY.filter(mouseY,mouseY,mouseQueueSize,offset);
mousepos[0] = (int)(pixelsPerMeter*mouseX[1]);
mousepos[1] = (int)(pixelsPerMeter*mouseY[1]);
float vx = (mouseX[1]-mouseX[0])*mouseSamplingRate;
float vy = (mouseY[1]-mouseY[0])*mouseSamplingRate;
float vSlide2 = vx*vx+vy*vy;
float vSlide = (float)Math.sqrt(vSlide2);
imagePixels = segmentDataProvider.getImagePixels();
imageDimension = segmentDataProvider.getImageDimension();
// if changing filter at run time mousepos[] may overflow
// remove pixels from sides so can average over 9 pixels
final int npixelsaround = 3;
final int npixels = (1 + 2*npixelsaround)*(1 + 2*npixelsaround);
if(mousepos[0]>=imageDimension.width-npixelsaround) {
mousepos[0]=imageDimension.width-npixelsaround-1;
} else if(mousepos[0]<npixelsaround) {
mousepos[0] = npixelsaround;
}
if(mousepos[1]>=imageDimension.height-npixelsaround) {
mousepos[1]=imageDimension.height-npixelsaround-1;
} else if(mousepos[1]<npixelsaround) {
mousepos[1] = npixelsaround;
}
rgb[0] = rgb[1] = rgb[2] = 0;
for(int x = mousepos[0]-npixelsaround;x<=mousepos[0]+npixelsaround;x++) {
for(int y = mousepos[1]-npixelsaround;y<=mousepos[1]+npixelsaround;y++) {
current_pixel = imagePixels[y * imageDimension.width + x];
tmprgb = pixel2rgb(current_pixel);
rgb[0] += tmprgb[0];
rgb[1] += tmprgb[1];
rgb[2] += tmprgb[2];
}
}
rgb[0] /= npixels;
rgb[1] /= npixels;
rgb[2] /= npixels;
float v = vSlide/unitScrapeVelocity;
if(segmentDataProvider.isMousePressed()) {
v = 1;
}
java.awt.Color.RGBtoHSB((int)rgb[0],(int)rgb[1],(int)rgb[2],hsb);
float pitch = (float)jass.utils.PitchMap.hue2pitch((double)hsb[0]);
colorSonificator.setHSB_V(pitch,hsb[1],hsb[2],v);
/*
// get lch luminance chromaticity and hue from L*a*b* space
rgb[0] /= 255;
rgb[1] /= 255;
rgb[2] /= 255;
lch = jass.utils.Color.Rgb2lch(rgb);
colorSonificator.setHSB_V(lch[2],lch[1],lch[0],v);
//System.out.println("hsb=("+hsb[0]+","+hsb[1]+","+hsb[2]+")");
*/
try {
if(haveSy) {
buf = resonantSurface.getBuffer(getTime());
} else {
buf = colorSonificator.getBuffer(getTime());
}
} catch(BufferNotAvailableException e) {
System.out.println(this+" "+e);
}
}
}