@initialize: ->
try
@c = new AudioContext
@gn = Sound.c.createGain()
@gn.gain.value = Config.soundVolume
@gn.connect Sound.c.destination
@isEnabled = true
catch error
@isEnabled = false
@playInterval = 60 / Config.soundTempo
@scheduleInterval = 1 / Config.fps * 2
@quantize = 0.5
@clear()
@initDrumParams()
@initDrumPatterns()
@random = new Random
@clear: ->
@s = []
@reset: ->
s.reset() for s in @s
@update: ->
return if Game.isPaused || !Game.running || !@isEnabled
ct = @c.currentTime
tt = ct + @scheduleInterval
s.update ct, tt for s in @s
@initDrumParams: ->
@drumParams = [
["sine",0,3,0,0.1740,0.1500,0.2780,20,528,2400,-0.6680,0,0,0.0100,0.0003,0,0,0,0.5000,-0.2600,0,0.1000,0.0900,1,0,0,0.1240,0]
["square",0,2,0,0,0,0.1,20,400,2000,-1,0,0,0,0.5,0,0,0,0.5,-0.5,0,0,0.5,1,0,0,0.75,-1]
["noise",0,2,0,0,0,0.1,1300,500,2400,1,-1,1,40,1,0,1,0,0,0,0,0.75,0.25,1,-1,1,0.25,-1]
["noise",0,2,0,0,0,0.05,2400,2400,2400,0,-1,0,0,0,-1,0,0,0,0,0,-0.15,0.1,1,1,0,1,1]
["noise",0,2,0,0.0360,0,0.2860,20,986,2400,-0.6440,0,0,0.0100,0.0003,0,0,0,0,0,0,0,0,1,0,0,0,0]
["saw",0,1,0,0.1140,0,0.2640,20,880,2400,-0.6000,0,0,0.0100,0.0003,0,0,0,0.5000,-0.3620,0,0,0,1,0,0,0,0]
["synth",0,2,0,0.2400,0.0390,0.1880,328,1269,2400,-0.8880,0,0,0.0100,0.0003,0,0,0,0.4730,0.1660,0,0.1700,0.1880,1,0,0,0.1620,0]
]
@initDrumPatterns: ->
@drumPatterns = [
'0000010000000001'
'0000100000001000'
'0000100100001000'
'0000100001001000'
'0000101111001000'
'0000100100101000'
'0000100000001010'
'0001000001000101'
'0010001000100010'
'0010001000100010'
'0100000010010000'
'1000100010001000'
'1010010010100101'
'1101000001110111'
'1000100000100010'
'1010101010101010'
'1000100011001000'
'1111000001110110'
'1111101010111010'
]
@generateDrumParam: (seed) ->
@generateParam seed, @drumParams
@generateSeParam: (type, seed) ->
@generateParam seed, @seParams[type], 0.75
@generateDrumPattern: (seed) ->
random = if seed != 0 then new Random(seed) else @random
dpsl = @drumPatterns.length
i = random.ri 0, dpsl - 1
dp = @drumPatterns[i]
dpl = dp.length
dpa = []
for i in [0..dpl - 1]
d = dp.charAt i
dpa.push if d == '1' then true else false
while random.r() < .5
ci = random.ri 0, dpsl - 1
cdp = @drumPatterns[ci]
for i in [0..dpl - 1]
cd = cdp.charAt i
c = if cd == '1' then true else false
dpa[i] = (!dpa[i]) != (!c)
gdp = ''
for d in dpa
gdp += if d then '1' else '0'
gdp
reset: ->
@isPlayingOnce = @isPlayingLoop = null
update: (ct, tt) ->
if @isPlayingOnce?
@isPlayingOnce = null
pi = Sound.playInterval * Sound.quantize
pt = ceil(ct / pi) * pi
if !@playedTime? || pt > @playedTime
@playLater pt
@playedTime = pt
return if !@isPlayingLoop?
if !@scheduledTime?
@scheduledTime =
ceil(ct / Sound.playInterval) * Sound.playInterval -
Sound.playInterval * @patternInterval
@patternIndex = 0
@calcNextScheduledTime()
@calcNextScheduledTime() while @scheduledTime < ct
while @scheduledTime <= tt
@playLater @scheduledTime
@calcNextScheduledTime()
return
calcNextScheduledTime: ->
pn = @pattern.length
sti = Sound.playInterval * @patternInterval
for i in [0..99]
@scheduledTime += sti
p = @pattern.charAt @patternIndex
@patternIndex = (@patternIndex + 1).lr 0, pn
break if p == '1'
return
playLater: (delay) ->
s = Sound.c.createBufferSource()
s.buffer = @buffer
s.connect Sound.gn
s.start = s.start || s.noteOn
s.start delay