/* garden of earthly delays
 *
 * original gen~ patch by Gregory Taylor
 * https://cycling74.com/2011/11/07/gen-tutorial-1-the-garden-of-earthly-delays/
 *
 * adapted to genish.js by thecharlie 5/2/2016
 * after executing code, use GUI (will appear top right) to control feedback network
 */
 
// passing string to data loads resource via xmlhttprequest.
// run rest of script once the audiofile has loaded
audiofile = data( './resources/audiofiles/dead-presidents.wav' ).then( ()=> {
  
// 'ssd', or single-sample delay,  is pseudonym for gen~ history, since history
//  is a default property of the window object in the browser...
feedback1 = ssd();feedback2 = ssd();feedback3 = ssd();feedback4 = ssd()
  
damp     = param( 'damping', .5 )
damp2    = param( 'damping2', .5 )
damp3    = param( 'damping3', .5 )
delayTime= param( 'delayTime', 11025 )
gateCtrl = param( 'feedbackRouter', 0 )
 
// read through audiofile sample by sample
in1 = peek( 
  audiofile, // data
  accum( 1,0,{ max:audiofile.buffer.length } ), // indexing
  { interp:'none', mode:'samples' } 			// attributes
)
 
//delay1In = add( in1, gate1.outputs[0], gate2.outputs[1], gate3.outputs[2], gate4.outputs[3] )
//delay2In = add( in1, gate1.outputs[1], gate2.outputs[0], gate3.outputs[3], gate4.outputs[2] )
//delay3In = add( in1, gate1.outputs[2], gate2.outputs[3], gate3.outputs[0], gate4.outputs[1] )
//delay4In = add( in1, gate1.outputs[3], gate2.outputs[2], gate3.outputs[1], gate4.outputs[0] )

network = [
  [0,1,2,3],
  [1,0,3,2],
  [2,3,0,1],
  [3,2,1,0]
]
 
feedback = [], gates = [], delayInputs = [], delays = [], foldedDelays = [], dampedFeedbacks = []
 
// create delay lines
for( let i = 0; i < network.length; i++ ) {
  feedback[ i ]  = ssd()
  gates[ i ] = gate( gateCtrl, feedback[ i ].out, { count: network.length })
  delayInputs[ i ] = add( in1 )
  delays[ i ] = delay( delayInputs[ i ], div( delayTime, i+1 ), { size:44100 })
  foldedDelays[ i ] = fold( delays[ i ], -1,1 )
  dampedFeedbacks[ i ] = mix( foldedDelays[ i ], feedback[ i ].out, i < 2 ? damp : damp2 )
  feedback[ i ].in( dampedFeedbacks[ i ] )
}
 
// now that all the gates / delay lines have been created, generate feedback network
for( let j = 0; j < network.length; j++ ) {
  let row = network[ j ], 
      addInputs = delayInputs[ j ].inputs
  
  for( let k = 0; k < row.length; k++ ) { 
    addInputs.push( gates[ k ].outputs[ row[ k ] ] ) 
  }
}

/*
j = 0, k = 0
row = [0,1,2,3]
addInputs = delayInputs[ 0 ].inputs

delayInputs[0].inputs.push( gates[0].outputs[ 0 ] )
delayInputs[0].inputs.push( gates[1].outputs[ 1 ] )
delayInputs[0].inputs.push( gates[2].outputs[ 2 ] )
delayInputs[0].inputs.push( gates[3].outputs[ 3 ] )

delayInputs[1].inputs.push( gates[0].outputs[ 1 ] )
delayInputs[1].inputs.push( gates[1].outputs[ 0 ] )
delayInputs[1].inputs.push( gates[2].outputs[ 3 ] )
delayInputs[1].inputs.push( gates[3].outputs[ 2 ] )
*/
//cb = play( add( ...dampedFeedbacks ) )

ssdLeft = ssd()
ssdRight = ssd()

inputsL = add(), inputsR = add()
 
for( let i = 0; i < network.length; i+= 2 ) {
  console.log( i )
  inputsL.inputs.push( dampedFeedbacks[ i ] )
  inputsR.inputs.push( dampedFeedbacks[ i+1 ] )  
}
 

//console.log( inputsL, inputsR )
  
left  = mix( mul( 1 / (network.length / 2), inputsL ), ssdLeft.out,  damp3 )
right = mix( mul( 1 / (network.length / 2), inputsR ), ssdRight.out, damp3 )
 
// record left and right output to use in next sample
ssdLeft.in( left )
ssdRight.in( right )

// limit output to {-1,1}
limitL = clamp( left, -1,1 )
limitR = clamp( right, -1,1 )
  
// play stereo out & print callback to console for potential debugging
cb = play( [ limitL, limitR ], true )

gui = new dat.GUI({ width:400 })
gui.add( cb, 'damping',   0, 1 )
gui.add( cb, 'damping2',  0, 1 )
gui.add( cb, 'damping3',  0, 1 )
gui.add( cb, 'delayTime', 128, 22050 )
gui.add( cb, 'feedbackRouter', 0, network.length - 1 ).step(1)
  
})
