// Doppler Effect // Doppler shift ( /* v = -140.0; // velocity of the moving object in km/h dmax = 200; // starting distance in meters c = 340.0; // speed of sound in meters per second dur = 10; // duration of the movement in seconds db = 0.5; // distance between the two microphones in meters ds = 10; // distance of microphones to the path of the object */ SynthDef("doppler", {arg v= -140, dmax=200, c=340, dur=10, db=0.5, ds=10; var distance, nspeed, dl, dr, dtl, dtr, source; nspeed = v * 1000/3600; distance = Line.kr(dmax, dur * nspeed + dmax, dur, doneAction: 2); dl = ((distance - (db/2)).squared + ds.squared).sqrt; dr = ((distance + (db/2)).squared + ds.squared).sqrt; dtl = dl / c; dtr = dr / c; source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], ds / [dl, dr])); }).play; ) // Doppler Effect, using hypot ( /* v = -140.0; // velocity of the moving object in km/h dmax = 200; // starting distance in meters c = 340.0; // speed of sound in meters per second dur = 10; // duration of the movement in seconds db = 0.5; // distance between the two microphones in meters ds = 10; // distance of microphones to the path of the object damping = 1.5;// exponent for sound pressure attenuation (1.0 ... 2.0) */ SynthDef("doppler2", {arg v= -140, dmax=200, c=340, dur=10, db=0.5, ds=10, damping=1.5; var distance, nspeed, dl, dr, dtl, dtr, source; nspeed = v * 1000/3600; distance = Line.kr(dmax, dur * nspeed + dmax, dur, doneAction: 2); dl = hypot( distance - (db/2), ds); dr = hypot( distance + (db/2), ds); dtl = dl / c; dtr = dr / c; source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], ds / [dl, dr] ** damping )); }).play; ) /* Aufgabe: Panning mit Doppler2 als Objekt (Pan0 kann als Modell fuer Implementierung dienen) Argumente: inputsignal, distanz des Objekts, winkel des Objekts, Mikrofonbasis, Daempfungsexponent Winkel in Grad: 0 Grad ist Mitte vorn, >0 links, <0 rechts Doppler2.ar(in, dist, angle, base, damp); Doppler2.ar(sig, 20, -45, 1, 1.5); 1. Schritt: Implementierung als SynthDef mit passenden Argumenten als FX-Synth oder testweise mit source und Out incl. eventuell mit Point arbeiten zur Berechnung der Distanzen 2. Schritt: optimieren 3. Schritt: Zur Klasse umschreiben (neue Datei: z.B. Doppler.sc, usw.) */ ( SynthDef("dopplertest", {arg dist=5.0, angle= 30, base=1.0, damping=1.5; var w, dl, dr, dtl, dtr, source, c=340.0; w = angle / 180 * pi; dl = sqrt(dist.squared + (base/2).squared - (2 * dist * base/2 * cos(pi/2 - w))); dr = sqrt(dist.squared + (base/2).squared - (2 * dist * base/2 * cos(pi/2 + w))); dtl = dl / c; dtr = dr / c; source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], base / [dl, dr] ** damping )); }).play; ) ( // optimierte (?) Variante SynthDef("dopplertest", {arg dist=5.0, angle= -30, base=1.0, damping=1.5; var w, t1, t2, p2, dl, dr, dtl, dtr, source, cr=340.0.reciprocal; w = angle * 180.reciprocal * pi; t1 = dist.squared + (base*0.5).squared; t2 = dist * base; p2 = pi * 0.5; dl = sqrt(t1 - (t2 * cos(p2 - w))); dr = sqrt(t1 - (t2 * cos(p2 + w))); dtl = dl * cr; dtr = dr * cr; source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], base * [dl, dr].reciprocal ** damping )); }).play; ) //-------------- doppler.sc ------ Doppler2 { classvar cr, p2, wnorm; *initClass { cr = 340.0.reciprocal; p2 = pi * 0.5; wnorm = 180.reciprocal * pi; } // dist [m], angle [degrees], base [m] *ar { arg in, dist=2.0, angle= 0.0, base=1.0, damping=1.5; var w, t1, t2, dl, dr, dtl, dtr; w = angle * wnorm; t1 = dist.squared + (base * 0.5).squared; t2 = dist * base; dl = sqrt(t1 - (t2 * cos(p2 - w))); dr = sqrt(t1 - (t2 * cos(p2 + w))); dtl = dl * cr; dtr = dr * cr; ^DelayC.ar(in, 10, [dtl, dtr], base * [dl, dr].reciprocal ** damping); } } //-------------- doppler.sc ------ ( SynthDef("test", { var sig, dist, angle, pan; sig = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(300)); // sig = RLPF.ar(FSinOsc.ar(200, 0, LFPulse.ar(31.3, 0, 0.4)), 400, 0.3); dist = MouseY.kr(20, 2); angle = MouseX.kr(30, -30); pan = Doppler2.ar(sig, dist, angle, damping: 1); Out.ar(0, pan); }).play; ) // ------ Doppler mit xy-Koordinaten statt Polarkoordinaten: ( y = SynthDef("dopplerxy", {arg size = 20, x=0, y=1, c=340, db=1.5, damping=1.5; var dl, dr, dtl, dtr, source; var x1, x2; //x = MouseX.kr(-1.0, 1.0); //y = MouseY.kr(1.0, 0.0); x1 = x + (db*0.5/size); x2 = x - (db*0.5/size); dl = hypot(x1, y) * size; dr = hypot(x2, y) * size; dtl = dl / c; dtr = dr / c; //source = WhiteNoise.ar(0.5); source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); //source = RLPF.ar(FSinOsc.ar(200, 0, LFPulse.ar(31.3, 0, 0.4, 0.5)), 400, 0.5); source = LPF.ar(source, [ dl, dr].linexp(0, size, 10000, 1000)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], 1 / [dl+1, dr+1] ** damping )); }, [0, 0.2, 0.2]).play; w = GUI.window.new("dopplertest", Rect(100, 300, 300, 300)); r = GUI.slider2D.new(w, Rect(10, 10, 280, 280)); r.action = { arg view; //[view.x, view.y].postln; y.set(\x, view.x - 0.5); y.set(\y, view.y); }; w.front; w.onClose = { y.free }; ) // ------ dito, aber unter Zuhilfenahme von Point: ( var size = 20; y = SynthDef("dopplerxy", {arg x=0, y=10, c=340, db=1.5, damping=1.5; var dl, dr, dtl, dtr, source; var pl, pr, ps; ps = Point(x,y); pl = Point(db * -0.5, 0); pr = Point(db * 0.5, 0); dl = ps.dist(pl); dr = ps.dist(pr); dtl = dl / c; dtr = dr / c; //source = WhiteNoise.ar(0.5); source = Decay.ar(Impulse.ar(30), 0.03, Saw.ar(600)); //source = RLPF.ar(FSinOsc.ar(200, 0, LFPulse.ar(31.3, 0, 0.4, 0.5)), 400, 0.5); source = LPF.ar(source, [ dl, dr].linexp(0, size, 10000, 1000)); Out.ar(0, DelayC.ar(source, 10, [dtl, dtr], 1 / [dl+1, dr+1] ** damping )); }, [0.2, 0.2]).play; w = GUI.window.new("dopplertest", Rect(100, 300, 300, 300)); r = GUI.slider2D.new(w, Rect(10, 10, 280, 280)); r.action = { arg view; //[view.x, view.y].postln; y.set(\x, view.x - 0.5 * size); y.set(\y, view.y * size); }; w.front; w.onClose = { y.free }; )