Random Sounds

#VRML V2.0 utf8

# load all sounds so cached
Sound { source AudioClip { url "Sounds/drm_clave.wav" } }
Sound { source AudioClip { url "Sounds/drm_cowbell.wav" } }
Sound { source AudioClip { url "Sounds/drm_snare.wav" } }
Sound { source AudioClip { url "Sounds/metal_mute_power.E1.wav" } }
Sound { source AudioClip { url "Sounds/drm_scratch.wav" } }
Sound { source AudioClip { url "Sounds/hat_closed.wav" } }

PROTO Voice [ 
		   eventIn MFString url
		   eventIn SFFloat pitch
		   eventIn SFTime startTime
		   eventIn SFTime stopTime
		  ]
{
   Sound { 
      spatialize FALSE minFront 100 maxFront 100 minBack 100 maxBack 100
      source DEF CLIP AudioClip { 
	 url IS url  pitch IS pitch  startTime IS startTime  stopTime IS stopTime }
   }
}

DEF VOICE1 Voice {}
DEF VOICE2 Voice {}
DEF VOICE3 Voice {}
DEF VOICE4 Voice {}
DEF VOICE5 Voice {}
DEF VOICE6 Voice {}

# voice is scheduled when alarm goes off
DEF ALARM1 TimeSensor {}
DEF ALARM2 TimeSensor {}
DEF ALARM3 TimeSensor {}
DEF ALARM4 TimeSensor {}
DEF ALARM5 TimeSensor {}
DEF ALARM6 TimeSensor {}

# used to start SCRIPT, can't use initialize since vrmlscript doesn't support Date object
DEF LOADED ProximitySensor { size 1000 1000 1000 }

# init and schedule voices
DEF SCRIPT Script {
   directOutput TRUE
   mustEvaluate TRUE
   eventIn SFTime loaded
   eventIn SFTime schedule1
   eventIn SFTime schedule2
   eventIn SFTime schedule3
   eventIn SFTime schedule4
   eventIn SFTime schedule5
   eventIn SFTime schedule6
   field MFNode voices [ USE VOICE1  USE VOICE2  USE VOICE3  USE VOICE4 USE VOICE5 USE VOICE6 ]
   field MFNode alarms [ USE ALARM1  USE ALARM2  USE ALARM3  USE ALARM4 USE ALARM5 USE ALARM6 ]   
   url "vrmlscript:

function randR(l,h) { return Math.random()*(h-l)+l; }

function initVoices() {
   voices[0].url = new MFString('Sounds/drm_clave.wav');
   voices[1].url = new MFString('Sounds/drm_cowbell.wav');
   voices[2].url = new MFString('Sounds/drm_snare.wav');
   voices[3].url = new MFString('Sounds/metal_mute_power.E1.wav');
   voices[4].url = new MFString('Sounds/drm_scratch.wav');
   voices[5].url = new MFString('Sounds/hat_closed.wav');
}

function setVoice(i, when) {
   voices[i].pitch = (Math.random()<.5) ? randR(.25, 1) : randR(1,4);
   voices[i].startTime = when+1;
   alarms[i].startTime = when+1;
   alarms[i].cycleInterval = randR(.5, 3);
}

function loaded(val) {
   initVoices();
   for(i=0; i<voices.length; i++) { setVoice(i, val + 3); }
}

function schedule1(val) { setVoice(0, val); }
function schedule2(val) { setVoice(1, val); }
function schedule3(val) { setVoice(2, val); }
function schedule4(val) { setVoice(3, val); }
function schedule5(val) { setVoice(4, val); }
function schedule6(val) { setVoice(5, val); }

"}     

# alarm sends cycleTime event at beginning and end, this ignores one at beginning
# filter out first cycleTime events from alarms
# (should be able to use isActive=false event instead?)
PROTO Filter [ eventIn SFTime ein   
	       eventOut SFTime eout ]
{
   Script {
      mustEvaluate TRUE
      eventIn SFTime ein IS ein
      eventOut SFTime eout IS eout
      field SFBool first TRUE
      url "vrmlscript: function ein(val) { if(first) { first=FALSE; } else { eout=val; first=TRUE; }}"
   }
}

DEF FILTER1 Filter {}
DEF FILTER2 Filter {}
DEF FILTER3 Filter {}
DEF FILTER4 Filter {}
DEF FILTER5 Filter {}
DEF FILTER6 Filter {}

ROUTE LOADED.enterTime TO SCRIPT.loaded
ROUTE ALARM1.cycleTime TO FILTER1.ein
ROUTE FILTER1.eout TO SCRIPT.schedule1
ROUTE ALARM2.cycleTime TO FILTER2.ein
ROUTE FILTER2.eout TO SCRIPT.schedule2
ROUTE ALARM3.cycleTime TO FILTER3.ein
ROUTE FILTER3.eout TO SCRIPT.schedule3
ROUTE ALARM4.cycleTime TO FILTER4.ein
ROUTE FILTER4.eout TO SCRIPT.schedule4
ROUTE ALARM5.cycleTime TO FILTER5.ein
ROUTE FILTER5.eout TO SCRIPT.schedule5
ROUTE ALARM6.cycleTime TO FILTER6.ein
ROUTE FILTER6.eout TO SCRIPT.schedule6


mrl