//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;
}
}