 ###
 class TinyRaveScheduler
   @createBlock: (duration, methods) ->
+    if arguments.length != 2
+      throw new Error "Must specify a duration and block methods for createBlock()"
     { duration: duration, methods: methods }
 
   constructor: ->


  push: (blocks...) ->
    for block in blocks
      console.warn "Push all blocks before the first call to buildSample. (Feel free to email me if you need this fixed.)" if @time > 0
      delay = @getBlockQueueLength()
      @blocks.push(block)
      TinyRave.setTimeout((=> @shiftBlock()), delay)

  shiftBlock: ->
    block = @blocks.shift()
    console.error "In shiftBlock(). No block left to shift." unless block?
    blockScope = new BlockScope block.duration
    block.methods.blockWillStart?.apply(blockScope)
    teardown = ->
      blockScope.blockWillEnd()
      block.methods.blockDidEnd?.apply(blockScope)
    TinyRave.setTimeout teardown, block.duration
    # We want to queue the teardown before any every/after calls. It seems most
    # natural to run all timers UP TO but not including block.duration. E.g., in
    # a block of length 12, with an every of 4, you want execution on 0 4 8 but
    # not 12. (12 is the down beat of the next block.)
    block.methods.run.apply(blockScope)


class BlockScope
  constructor: (@duration) ->
    @timerIds = []
  getDuration: -> @duration
  every: (delay, callback) ->
    callback.apply(@) # Fire first iteration immediately
    id = TinyRave.setInterval((=> callback.apply(@)), delay)
    @timerIds.push id
  after: (delay, callback) ->
    id = TinyRave.setTimeout((=> callback.apply(@)), delay)
    @timerIds.push id
  blockWillEnd: ->
    for id in @timerIds
      TinyRave.clearInterval id

#
# TinyRave Object

TinyRave.setBPM = (bpm) ->
  TinyRave.BPM = bpm

setInterval = (callback, delay) ->
  TinyRave.scheduler.registerCallback(callback, delay, TinyRave.scheduler.getTime(), true)

setTimeout = (callback, delay) ->
  TinyRave.scheduler.registerCallback(callback, delay, TinyRave.scheduler.getTime(), false)

clearInterval = (id) ->
  # This can work for setTimeout calls, too, unlike native setTimeout.
  TinyRave.scheduler.unregisterCallback(id)
  undefined
