<commit_before>Ajax = require "./lib/ajax"

clone = (obj) ->
  JSON.parse(JSON.stringify(obj))

module.exports = (context, Player) ->
  readFile = require "./lib/read_file"
  Drop = require "./lib/drop"

  Drop document, (e) ->
    file = e.dataTransfer.files[0]

    if file
      readFile(file, "readAsArrayBuffer")

  loadFile = (file) ->

  # Midi loading
  MidiFile = require "./lib/midifile"
  MidiPlayer = require "./midi_player"

  # Bad Apple 36MB MIDI
  badApple = "http://whimsy.space/danielx/data/clOXhtZz4VcunDJZdCM8T5pjBPKQaLCYCzbDod39Vbg"
  waltz = "http://whimsy.space/danielx/data/qxIFNrVVEqhwmwUO5wWyZKk1IwGgQIxqvLQ9WX0X20E"
  jordan = "http://whimsy.space/danielx/data/FhSh0qeVTMu9Xwd4vihF6shaPJsD_rM8t1OSKGl-ir4"
  aquarius = "http://whimsy.space/danielx/data/ZZXoIXhXFbo0pWGn-m938Vgox_NmJiYkZ9g3UkR0PrU"
  slunk = "http://whimsy.space/danielx/data/EtME8Imvk8eE8MXc7jlwJOVotKM2KVmxXd8QiJtBbPc"

  {playNote, releaseNote, programChange, pitchBend} = Player()

  meta = {}

  handleEvent = (event, state) ->
    {time, timeOffset} = state
    {channel, deltaTime, noteNumber, subtype, type, velocity} = event

    # TODO: Should we just pass through the raw midi event data buffers directly
    # rather than switch and dispatch known subsets here?
    switch "#{type}:#{subtype}"
      when "channel:controller"
        ; # TODO
      when "channel:noteOn"
        playNote time + timeOffset, channel, noteNumber, velocity
      when "channel:noteOff"
        releaseNote time + timeOffset, channel, noteNumber
      when "channel:pitchBend"
        pitchBend time, channel, event.value
      when "channel:programChange"
        programChange time, channel, event.programNumber
      when "meta:copyrightNotice"
        if meta.copyrightNotice
          meta.copyrightNotice += "/n#{event.text}"
        else
          meta.copyrightNotice = event.text
      when "meta:endOfTrack"
        ; # TODO
      when "meta:keySignature"
        meta.keySignature =
          scale: event.scale
          key: event.key
      when "meta:lyrics"
        ; # TODO
      when "meta:setTempo"
        state.microsecondsPerBeat = event.microsecondsPerBeat
      when "meta:text"
        if meta.text
          meta.text += "/n#{event.text}"
        else
          meta.text = event.text
      when "meta:timeSignature"
        meta.timeSignature =
          denominator: event.denominator
          metronome: event.metronome
          numerator: event.numerator
          thirtyseconds: event.thirtySeconds
      when "meta:trackName"
        # TODO: This needs to be per track
        meta.trackName = event.text
      when "meta:unknown"
        ;
      else
        console.log "Unknown", event

    return state

  initialState = null
  currentState = null
  playing = false

  Ajax.getBuffer(aquarius)
  .then (buffer) ->
    array = new Uint8Array(buffer)
    midiFile = MidiFile(array)
    console.log midiFile

    player = MidiPlayer(midiFile)

    currentState = initialState = clone(player.initialState)
    currentState.timeOffset = context.currentTime

    consumeEventsUntilTime = (t) ->
      count = 0

      while currentState.time < t
        [event, nextState] = player.readEvent(currentState, true)
        break unless event
        currentState = handleEvent(event, nextState)
        count += 1

      return count

    setInterval ->
      if playing
        consumed = consumeEventsUntilTime(context.currentTime - currentState.timeOffset + 0.025)
        # console.log "Consumed:", consumed
    , 4

  play: ->
    playing = true

  pause: ->
    playing = !playing

  stop: ->
    playing = false
    currentState = initialState<commit_msg>:b::rat: Updated in browser at strd6.github.io/editor<commit_after>Ajax = require "./lib/ajax"

clone = (obj) ->
  JSON.parse(JSON.stringify(obj))

module.exports = (context, Player) ->
  readFile = require "./lib/read_file"
  Drop = require "./lib/drop"

  Drop document, (e) ->
    file = e.dataTransfer.files[0]

    if file
      readFile(file, "readAsArrayBuffer")

  loadFile = (file) ->

  # Midi loading
  MidiFile = require "./lib/midifile"
  MidiPlayer = require "./midi_player"

  # Bad Apple 36MB MIDI
  badApple = "http://whimsy.space/danielx/data/clOXhtZz4VcunDJZdCM8T5pjBPKQaLCYCzbDod39Vbg"
  waltz = "http://whimsy.space/danielx/data/qxIFNrVVEqhwmwUO5wWyZKk1IwGgQIxqvLQ9WX0X20E"
  jordan = "http://whimsy.space/danielx/data/FhSh0qeVTMu9Xwd4vihF6shaPJsD_rM8t1OSKGl-ir4"
  aquarius = "http://whimsy.space/danielx/data/ZZXoIXhXFbo0pWGn-m938Vgox_NmJiYkZ9g3UkR0PrU"
  slunk = "http://whimsy.space/danielx/data/EtME8Imvk8eE8MXc7jlwJOVotKM2KVmxXd8QiJtBbPc"

  {playNote, releaseNote, programChange, pitchBend} = Player()

  meta = {}

  handleEvent = (event, state) ->
    {time, timeOffset} = state
    {channel, deltaTime, noteNumber, subtype, type, velocity} = event

    # TODO: Should we just pass through the raw midi event data buffers directly
    # rather than switch and dispatch known subsets here?
    switch "#{type}:#{subtype}"
      when "channel:controller"
        ; # TODO
      when "channel:noteOn"
        playNote time + timeOffset, channel, noteNumber, velocity
      when "channel:noteOff"
        releaseNote time + timeOffset, channel, noteNumber
      when "channel:pitchBend"
        pitchBend time, channel, event.value
      when "channel:programChange"
        programChange time, channel, event.programNumber
      when "meta:copyrightNotice"
        if meta.copyrightNotice
          meta.copyrightNotice += "/n#{event.text}"
        else
          meta.copyrightNotice = event.text
      when "meta:endOfTrack"
        ; # TODO
      when "meta:keySignature"
        meta.keySignature =
          scale: event.scale
          key: event.key
      when "meta:lyrics"
        ; # TODO
      when "meta:setTempo"
        state.microsecondsPerBeat = event.microsecondsPerBeat
      when "meta:text"
        if meta.text
          meta.text += "/n#{event.text}"
        else
          meta.text = event.text
      when "meta:timeSignature"
        meta.timeSignature =
          denominator: event.denominator
          metronome: event.metronome
          numerator: event.numerator
          thirtyseconds: event.thirtySeconds
      when "meta:trackName"
        # TODO: This needs to be per track
        meta.trackName = event.text
      when "meta:unknown"
        ;
      else
        console.log "Unknown", event

    return state

  initialState = null
  currentState = null
  playing = false

  Ajax.getBuffer(aquarius)
  .then (buffer) ->
    array = new Uint8Array(buffer)
    midiFile = MidiFile(array)
    console.log midiFile

    player = MidiPlayer(midiFile)

    initialState = clone(player.initialState)
    
    currentState = clone(initialState)
    currentState.timeOffset = context.currentTime

    consumeEventsUntilTime = (t) ->
      count = 0

      while currentState.time < t
        [event, nextState] = player.readEvent(currentState, true)
        break unless event
        currentState = handleEvent(event, nextState)
        count += 1

      return count

    setInterval ->
      if playing
        consumed = consumeEventsUntilTime(context.currentTime - currentState.timeOffset + 0.025)
        # console.log "Consumed:", consumed
    , 4

  play: ->
    playing = true

  pause: ->
    playing = !playing

  stop: ->
    playing = false
{'fraction_non_alphanumeric': 0.1002031144211239, 'fraction_numerical': 0.011509817197020988, 'mean_word_length': 2.6782868525896415, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5181413', 'n_tokens_mistral': 2507, 'n_tokens_neox': 2400, 'n_words': 505}