combFilter = function( _input, combLength, damping=.5*.4, feedbackCoeff=.84 ) {
  let lastSample = ssd(),
  	  readWriteIdx = counter( 1,0,combLength ),
      combBuffer = data( combLength ),
	  out = peek( combBuffer, readWriteIdx, { interp:'none', mode:'samples' }),
      storeInput = memo( add( mul( out, sub( 1, damping)), mul( lastSample.out, damping ) ) )
      
  lastSample.in( storeInput )
 
  poke( combBuffer, add( _input, mul( storeInput, feedbackCoeff ) ), readWriteIdx )
 
  return out
}
 
// constructor for schroeder allpass filters
allPass = function( _input, length=500, feedback=.5 ) {
  let index  = counter( 1,0,length ),
      buffer = data( length ),
      bufferSample = peek( buffer, index, { interp:'none', mode:'samples' }),
      out = memo( add( mul( -1, _input), bufferSample ) )
                
  poke( buffer, add( _input, mul( bufferSample, feedback ) ), index )
 
  return out
}
 
// tuning settings for schroeder / moorer model
tuning = {
  combCount:		8,
  combTuning: 		[ 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 ],                    
  allPassCount: 	4,
  allPassTuning:	[ 225, 556, 441, 341 ],
  allPassFeedback:  0.5,
  fixedGain: 		0.015,
  scaleDamping: 	0.4,
  scaleRoom: 		0.28,
  offsetRoom: 	    0.7,
}
 
combs = []

signalData = data( './resources/audiofiles/dead-presidents.wav' ).then( ()=> {
  // parameters for external manipulation (via gui)
  let wet = param( 'wet',.55 ), dry = param( 'dry',.5 ), 
      roomSize = param( 'roomSize',75 ), bandwidth = param( 'bandwidth', .5 ),
      early = param( 'early', .25 ), revtime = param( 'revtime', 11 )
  
  in1 = in2 = peek( signalData, accum( 1,0, { max:signalData.buffer.length } ), { interp:'none', mode:'samples' } )
 
  attenuatedSignal = memo( mul( in1, .707 ) )
  
  // in1 * samplerate / 340
  roomSizeCoeff = memo( div( mul( roomSize, gen.samplerate ), 340 ) )
  
  // input damper
  damperHistory = ssd()
  damper = mix( attenuatedSignal, damperHistory.out, sub( 1, bandwidth ) )
  damperHistory.in( damper )
  
  prediffuseHistory = ssd()
  prediffuseTime  = mul( roomSizeCoeff, .110732 )
  prediffuseDelay = delay( prediffuseHistory.out, prediffuseTime, { size: 6000 })
  
  dampMinusDiffuse = sub( damper, mul( prediffuseDelay, .75 ) )
  prediffuseHistory.in( dampMinusDiffuse )
  
  prediffusePlusDamping = add( prediffuseDelay, mul( dampMinusDiffuse, .75 ) )
  
  tap1Time = memo( add( mul( roomSizeCoeff, .41 ), 5 ) )
  tap2Time = memo( add( mul( roomSizeCoeff, .3 ), 5 ) )
  tap3Time = memo( add( mul( roomSizeCoeff, .155 ), 5 ) )
  tap4Time = add( roomSizeCoeff, 5 )
  multitap = delay( 
    prediffusePlusDamping, 
   	tap1Time, tap2Time, tap3Time, tap4Time,
    { size: 48000, interp:'linear' }
  )
  
  //play( add( ...multitap.outputs ) )
  
  // pow( pow( 10,-60/20 ), 1. / ( in1*samplerate ) )
  tapCoeff = memo( pow( pow( 10,-60/20 ), div(1., mul( revtime, gen.samplerate) ) ) )
  
  
  tap1 = mul( early, mul( multitap.outputs[0], pow( tapCoeff, tap1Time ) ) )
  tap2 = mul( early, mul( multitap.outputs[1], pow( tapCoeff, tap2Time ) ) )
  tap3 = mul( early, mul( multitap.outputs[2], pow( tapCoeff, tap3Time ) ) )
  tap4 = mul( early, mul( multitap.outputs[3], pow( tapCoeff, tap4Time ) ) )
  
  tapsL = add( tap1, tap3 )
  tapsR = add( tap2, tap4 )
  tapOutput = sub( tapsL, tapsR )
  
  cb = play( tapOutput )
})  