/**
Simple Doppler effect simulator. Drag the sliders to change the speed of "sound", the frequency of the source, and the resolution of the simulation. The velocity of the source, and hence the amount of doppler shifting is determined by its distance from the center. Click to reposition it.
*/ import javax.vecmath.*; PFont font; float vSound = 40; float fSound = 5; int resolution = 5; int centerX, centerY; float mouseScale; Vector2f vSource; int controlWidth = 100, controlHeight; int viewWidth, viewHeight; int sourceX, sourceY; // Mouse is grabbing and dragging the source. boolean sourceGrabbed = false; float t; Slider vSoundSlider, fSoundSlider, resolutionSlider; ArrayList sliders; String message = "**************\n* Dopplifier *\n**************\n\nXavier\nSnelgrove\n2006\n\nFor Dix"; void setup() { size(500,400); viewWidth = width-controlWidth; viewHeight = height; controlHeight = height; font = loadFont("Monaco-10.vlw"); textFont(font,10); centerX = viewWidth/2; centerY = viewHeight/2; sourceX = centerX; sourceY = centerY; // set mouseScale so you can never exceed the speed of sound vSource = new Vector2f(); colorMode(HSB); vSoundSlider = new Slider(viewWidth+20,10,0,9,5.3, color(100,255,255), "v"); fSoundSlider = new Slider(viewWidth+50,10,0,9,1, color(150,255,255),"f"); resolutionSlider = new Slider(viewWidth+80,10,1,10,5, color(200,255,255), "res"); sliders = new ArrayList(); sliders.add(vSoundSlider); sliders.add(fSoundSlider); sliders.add(resolutionSlider); rectMode(CORNER); ellipseMode(CENTER); noStroke(); } void draw() { t = millis()/1000.0; vSound = vSoundSlider.val; fSound = fSoundSlider.val; resolution = int(resolutionSlider.val); mouseScale = vSound/dist(centerX,centerY,0,0); // sourceX = mouseX; // sourceY = mouseY; vSource.x = (sourceX - centerX)*mouseScale; vSource.y = (sourceY - centerY)*mouseScale; noStroke(); for (int x = 0; x <= viewWidth; x+=resolution) { for (int y = 0; y <= viewHeight; y+=resolution) { // the little plus resolution/2 thingies make each box have the colour // of the point in its center. This means that when you click you are // placing the source, and not clicking above-left of the source. color c = amp(x+resolution/2,y+resolution/2); fill(c); rect(x, y, resolution, resolution); } } fill(0); rect(viewWidth,0,controlWidth,height); for (int i = 0; i < sliders.size(); i++) { ((Slider) sliders.get(i)).draw(); } // Draw Logo fill(color(255,255,255)); translate(viewWidth+5,height*0.6); text(message,0,0); } color amp(int x, int y) { Vector2f toSource = new Vector2f(sourceX-x, sourceY-y); float l = toSource.length(); // Speed of the source in the component facing the spot of interest. float vRel = (vSource.dot(toSource)/l); // from Doppler formulas. float freq = fSound * (1 - vRel/vSound); //float freq = fSound * (vSound/(vSound+vRel)); float lamda = vSound/freq; color result = color(100*(sin(l/lamda - t*vSound)+1)); // color result = color(20*(sin(l/lamda - t)+1),255,255); return result; } void mousePressed() { if (mouseX > 0 && mouseX < viewWidth && mouseY > 0 && mouseY < viewHeight) { sourceGrabbed = true; sourceX = mouseX; sourceY = mouseY; } for (int i = 0; i < sliders.size(); i++) { ((Slider) sliders.get(i)).mousePressed(); } } void mouseReleased() { if (sourceGrabbed) sourceGrabbed = false; for (int i = 0; i < sliders.size(); i++) { ((Slider) sliders.get(i)).mouseReleased(); } } void mouseDragged() { if(sourceGrabbed) { sourceX = mouseX; sourceY = mouseY; } for (int i = 0; i < sliders.size(); i++) { ((Slider) sliders.get(i)).mouseDragged(); } } class Slider { int length = 100; int handleW = 10; int handleH = 10; color c; float max, min, val; String name; boolean grabbed = false; float pixPerUnit; // Top left corner int x, y; Slider(int _x, int _y, float _min, float _max, float _val, color _c, String _name) { x = _x; y = _y; max = _max; min = _min; val = _val; name = _name; c = _c; pixPerUnit = length/(max-min); } void draw() { pushMatrix(); translate(x,y); stroke(c); noFill(); line(handleW/2, 0, handleW/2, length); rectMode(CORNER); rect(0, (val-min)*pixPerUnit, handleW, handleH); rotate(HALF_PI); translate(0,handleW); fill(c); text(name,0,0); popMatrix(); } void mousePressed() { if (mouseX>x && mouseX < x+handleW && mouseY > y+(val-min)*pixPerUnit && mouseY < y+(val-min)*pixPerUnit + handleH) { grabbed = true; } } void mouseReleased() { if(grabbed) grabbed = false; println(name + ": " + val); } void mouseDragged() { if (grabbed) { val = (mouseY-y)/pixPerUnit; val = val>max?max:val; val = val