//Static point sound source with a very simple head releated transfer function. //Does amplitude attenuation and interaural delay but incorrectly responds to fast movements. //By: Pyry Pakkanen (Frostburn) frostburn@suomi24.fi /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ class StaticPSS{ //StaticPointSoundSource //It's assumed that the receivers (ears) lie along the x-axis. //The positive y direction is forward. -1.0 => float left_receiver; //the left ear lies at (-1.0, 0.0) 1.0 => float right_receiver; //the right ear lies at (1.0, 0.0) //According to wikipedia: "interaural time difference" (ITD). ITDmax = 0.63 ms Std.fabs(right_receiver-left_receiver)/((0.63::ms)/samp) => float speed_of_sound; //Location of the sound source: 0.0 => float x; 1.0 => float y; //Start out in front //0.0 => float z; 0.0 => float extraDistance; //Echo sources need this. Gain in; Pan2 out; in => LPF leftLPF => DelayA leftDelay => out.left; in => Gain leftDry => leftDelay; in => LPF rightLPF => DelayA rightDelay => out.right; in => Gain rightDry => rightDelay; second => leftDelay.max => rightDelay.max; update(); fun void update(){ float dist; 1.0/Math.sqrt(x*x+y*y) => float inorm; distance(x,y,left_receiver,0) + extraDistance => dist; (dist/speed_of_sound )::samp => leftDelay.delay; 1.0/dist => leftDelay.gain; -x*inorm*1000.0+4000.0 => leftLPF.freq; x*inorm*0.5+0.5 => leftLPF.gain; 0.8 => leftLPF.Q; -x*inorm*0.5 + y*inorm*0.1 + 0.4 => leftDry.gain; distance(x,y,right_receiver,0) + extraDistance => dist; (dist/speed_of_sound )::samp => rightDelay.delay; 1.0/dist => rightDelay.gain; x*inorm*1000.0+4000.0 => rightLPF.freq; -x*inorm*0.5+0.5 => leftLPF.gain; 0.8 => rightLPF.Q; x*inorm*0.5 + y*inorm*0.1 + 0.4 => rightDry.gain; } fun void setLocation(float _x, float _y){ _x => x; _y => y; update(); } fun void setPolar(float radius,float angle){ //angle in radians Math.cos(angle)*radius => x; Math.sin(angle)*radius => y; update(); } fun float distance(float x1,float y1,float x2,float y2){ return Math.sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) ); } //UnitGen imitation: fun UGen chuck(UGen @ u){ //u => me.chuck => something_further u => in; return out; } fun UGen unchuck(UGen @ u){ //u => me.unchuck =< something_further u =< in; return out; } fun float gain(){ return out.gain(); } fun float gain(float gain){ return gain => out.gain; } } Pan2 output => dac; 5 => int N; //How many dripping shreds to spork for(0 => int i; i < N; i++) spork~droppy(output); day => now; fun void droppy(UGen out){ StaticPSS p; Shakers s => p.chuck => out; while(true){ p.setPolar( Std.rand2f(3.0,10.0), Std.rand2f(0.0,2.0*pi) ); //Set a random position from three to ten units away from the listener //Drop a drop: 4 => s.preset; //Select raindrop 7.0 => s.noteOn; //Shakers already randomizes everything nicely Std.rand2f(30.0,50.0)::ms => now; //Wait for the drop to play out. (StaticPSS doesn't like to be moved suddenly while playing) 1.0 => s.noteOff; } }