local love = love
local passChimes = {}
local failChimes = {}
local wineChimes = {}
local drones = {}
local N = 12

love.audio.setDistanceModel( "exponentclamped" )

local function StartDrones()
  love.audio.setEffect( "droneReverb", {
      type = "reverb",
      volume = 1.0,
      decaytime = 20}

)

  drones.wail = love.audio.newSource("sounds/drone3.flac", "stream")
  drones.fuck = love.audio.newSource("sounds/noiseloop.flac", "static" )
  drones.subs = love.audio.newSource("sounds/27Hz.flac", "static" )
  drones.bass = love.audio.newSource("sounds/drone.flac", "stream")  
  drones.alto = love.audio.newSource("sounds/drone.flac", "stream")
  
  drones.subs:setLooping( true )
  drones.subs:setVolume( 0 )
  drones.subs:setPitch( 2.0 )
  --drones.subs:setEffect( "droneReverb", true )
  drones.subs:stop()

  drones.bass:setLooping( true )
  drones.bass:setVolume( 0 )
  drones.bass:setPitch( 0.25 )
  drones.bass:setEffect( "droneReverb", true )
  drones.bass:stop()
  
  drones.alto:setLooping( true )
  drones.alto:setVolume( 0 )
  drones.alto:setPitch( 2 )
  drones.alto:setEffect( "droneReverb", true )
  drones.alto:stop()
  
  drones.fuck:setLooping( true )
  drones.fuck:setVolume( 0 )
  drones.fuck:setPitch( 1.0 )
  drones.fuck:setEffect( "droneReverb", true )
  drones.fuck:stop()
  
  drones.wail:setLooping( true )
  drones.wail:setVolume( 0 )
  drones.wail:setPitch( 1.0 )
  drones.wail:setEffect( "droneReverb", true )
  drones.wail:stop()
  
  love.audio.play( drones.bass )
  love.audio.play( drones.alto )
  love.audio.play( drones.fuck )
  love.audio.play( drones.subs )
  love.audio.play( drones.wail )
end

love.audio.setEffect( "passChimeReverb", {
    type = "reverb",
    volume = 1.0,
    gain = 1.0,} )

local wineChime = love.audio.newSource("sounds/chimewinedolce.flac", "static")
wineChime:setEffect( "passChimeReverb", true )
local passChime = love.audio.newSource("sounds/chimeb.flac", "static")
passChime:setEffect( "passChimeReverb", true )
local failChime = love.audio.newSource("sounds/chime.flac", "static")
failChime:setEffect( "passChimeReverb", true )

for i = 1, N do
  wineChimes[i] = wineChime:clone()
  passChimes[i] = passChime:clone()
  failChimes[i] = failChime:clone()
end

local idxNextPassChime = 1
local idxNextFailChime = 1
local idxNextWineChime = 1
local function GetNextPassChime(  )
  idxNextPassChime = idxNextPassChime % N + 1
  return passChimes[ idxNextPassChime ]
end

local function GetNextFailChime(  )
  idxNextFailChime = idxNextFailChime % N + 1
  return failChimes[ idxNextFailChime ]
end

local function GetNextWineChime(  )
  idxNextWineChime = idxNextWineChime % N + 1
  return wineChimes[ idxNextWineChime ]
end

local pitches = 
{
  1/2,
  3/4,
  1,
  2/3,
  3/2,
  9/8,
  27/16,
  81/64,
  243/128,
  2 --Safety
}

local function GetPitch( th )
  th = 0.5 + 0.5 * th / math.pi
  return pitches[ 1 + math.floor( th * 9 )]
end

local function OnImpact( impact, score, pass, level )

  --
  if not pass then
    --drones.bass:seek( level )
    -- drones.alto:seek( level )
  else
    
    love.audio.setEffect( "passChimeReverb", {
    type = "reverb",
    volume = 1.0, 
    gain = 0.1 + 0.9 * level / 120,
    highgain = 0.3,} )
    
  end

  local th = impact.th
  local r = impact.r

  -- Chimes 
  local chime = pass and GetNextPassChime() or GetNextFailChime()
  chime:setPitch( GetPitch( th ) )
  chime:setPosition( 2.0 * r * math.cos( th ), 2.0 * r * math.sin( th ) )
  chime:setVolume( 0.1 + 0.9 * level / 120.0 )
  local highgain = math.max( 0, math.min( score, 1.0 ) - (pass and 0.5 or 0.9))
  chime:setFilter{
    type = "lowpass",
    volume = 0.5 * impact.speed,
    highgain = highgain,
  }
  love.audio.stop( chime )
  love.audio.play( chime )
  
  local wineChime = GetNextWineChime()
  wineChime:setPitch( GetPitch( th ) )
  wineChime:setPosition( love.math.random(), love.math.random() )
  wineChime:setVolume( 0.2 * impact.speed * math.max( 0.0, level / 60.0 - 0.5 ) )
  
  love.audio.stop( wineChime )
  love.audio.play( wineChime )

end

local function OnVictory( )
  love.audio.setEffect( "passChimeReverb", {
      type = "reverb",
      volume = 1.0,
      decaytime = 20,
      lategain = 9.5,
      gain = 1.0,
      } )
  
    love.audio.setEffect( "droneReverb", {
      type = "reverb",
      volume = 1.0,
      decaytime = 20,
      lategain = 10,
      gain = 1.0,} )
end

--score is the hypothetical "beat score" that would be attained
--if an impact took place at this instant.
local function Update( score, level )

  if level > 2 then
    level = level / 120.0
    drones.bass:setVolume( 0.7 * (0.2 + math.pow( score, 0.25 )) * level )
    drones.alto:setVolume( 0.3 * (0.3 + math.pow( score, 0.25 )) *  level  * level)
    drones.fuck:setVolume( 4.0 * math.max( 0, level - 0.75 ))
    drones.subs:setVolume( 0.5 * math.max( 0, level - 0.5  ))
    drones.wail:setVolume( 2.0 * math.max( 0, level - 0.666 ))
  end

end

local function Reset( )
  for i = 1, N do
    love.audio.stop( passChimes[i] )
    love.audio.stop( failChimes[i] )
    love.audio.stop( wineChimes[i] )
  end
  
  for _, drone in pairs(drones) do
    love.audio.stop( drone )
  end
  StartDrones()
end

Reset()
return { OnImpact = OnImpact, Update = Update, Reset = Reset, OnVictory = OnVictory}