{"version":3,"sources":["jsdelivr-header.js","/npm/midi-player-js@2.0.7/browser/midiplayer.js"],"names":[],"mappings":"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","file":"/npm/midi-player-js@2.0.7/browser/midiplayer.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.37.0.\n * Original file: /npm/midi-player-js@2.0.7/browser/midiplayer.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","var MidiPlayer = (function () {\n  'use strict';\n\n  function _typeof(obj) {\n    \"@babel/helpers - typeof\";\n\n    if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n      _typeof = function (obj) {\n        return typeof obj;\n      };\n    } else {\n      _typeof = function (obj) {\n        return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n      };\n    }\n\n    return _typeof(obj);\n  }\n\n  function _classCallCheck(instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  }\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  /**\n   * Constants used in player.\n   */\n  var Constants = {\n    VERSION: '2.0.7',\n    NOTES: [],\n    CIRCLE_OF_FOURTHS: ['C', 'F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb', 'Bbb', 'Ebb', 'Abb'],\n    CIRCLE_OF_FIFTHS: ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'D#', 'A#', 'E#']\n  }; // Builds notes object for reference against binary values.\n\n  var allNotes = [['C'], ['C#', 'Db'], ['D'], ['D#', 'Eb'], ['E'], ['F'], ['F#', 'Gb'], ['G'], ['G#', 'Ab'], ['A'], ['A#', 'Bb'], ['B']];\n  var counter = 0; // All available octaves.\n\n  var _loop = function _loop(i) {\n    allNotes.forEach(function (noteGroup) {\n      noteGroup.forEach(function (note) {\n        return Constants.NOTES[counter] = note + i;\n      });\n      counter++;\n    });\n  };\n\n  for (var i = -1; i <= 9; i++) {\n    _loop(i);\n  }\n\n  /**\n   * Contains misc static utility methods.\n   */\n  var Utils = /*#__PURE__*/function () {\n    function Utils() {\n      _classCallCheck(this, Utils);\n    }\n\n    _createClass(Utils, null, [{\n      key: \"byteToHex\",\n\n      /**\n       * Converts a single byte to a hex string.\n       * @param {number} byte\n       * @return {string}\n       */\n      value: function byteToHex(_byte) {\n        // Ensure hex string always has two chars\n        return ('0' + _byte.toString(16)).slice(-2);\n      }\n      /**\n       * Converts an array of bytes to a hex string.\n       * @param {array} byteArray\n       * @return {string}\n       */\n\n    }, {\n      key: \"bytesToHex\",\n      value: function bytesToHex(byteArray) {\n        var hex = [];\n        byteArray.forEach(function (_byte2) {\n          return hex.push(Utils.byteToHex(_byte2));\n        });\n        return hex.join('');\n      }\n      /**\n       * Converts a hex string to a number.\n       * @param {string} hexString\n       * @return {number}\n       */\n\n    }, {\n      key: \"hexToNumber\",\n      value: function hexToNumber(hexString) {\n        return parseInt(hexString, 16);\n      }\n      /**\n       * Converts an array of bytes to a number.\n       * @param {array} byteArray\n       * @return {number}\n       */\n\n    }, {\n      key: \"bytesToNumber\",\n      value: function bytesToNumber(byteArray) {\n        return Utils.hexToNumber(Utils.bytesToHex(byteArray));\n      }\n      /**\n       * Converts an array of bytes to letters.\n       * @param {array} byteArray\n       * @return {string}\n       */\n\n    }, {\n      key: \"bytesToLetters\",\n      value: function bytesToLetters(byteArray) {\n        var letters = [];\n        byteArray.forEach(function (_byte3) {\n          return letters.push(String.fromCharCode(_byte3));\n        });\n        return letters.join('');\n      }\n      /**\n       * Converts a decimal to it's binary representation.\n       * @param {number} dec\n       * @return {string}\n       */\n\n    }, {\n      key: \"decToBinary\",\n      value: function decToBinary(dec) {\n        return (dec >>> 0).toString(2);\n      }\n      /**\n       * Reads a variable length value.\n       * @param {array} byteArray\n       * @return {number}\n       */\n\n    }, {\n      key: \"readVarInt\",\n      value: function readVarInt(byteArray) {\n        var result = 0;\n        byteArray.forEach(function (number) {\n          var b = number;\n\n          if (b & 0x80) {\n            result += b & 0x7f;\n            result <<= 7;\n          } else {\n            /* b is the last byte */\n            result += b;\n          }\n        });\n        return result;\n      }\n      /**\n       * Decodes base-64 encoded string\n       * @param {string} string\n       * @return {string}\n       */\n\n    }, {\n      key: \"atob\",\n      value: function (_atob) {\n        function atob(_x) {\n          return _atob.apply(this, arguments);\n        }\n\n        atob.toString = function () {\n          return _atob.toString();\n        };\n\n        return atob;\n      }(function (string) {\n        if (typeof atob === 'function') return atob(string);\n        return new Buffer(string, 'base64').toString('binary');\n      })\n    }]);\n\n    return Utils;\n  }();\n\n  /**\n   * Class representing a track.  Contains methods for parsing events and keeping track of pointer.\n   */\n\n  var Track = /*#__PURE__*/function () {\n    function Track(index, data) {\n      _classCallCheck(this, Track);\n\n      this.enabled = true;\n      this.eventIndex = 0;\n      this.pointer = 0;\n      this.lastTick = 0;\n      this.lastStatus = null;\n      this.index = index;\n      this.data = data;\n      this.delta = 0;\n      this.runningDelta = 0;\n      this.events = [];\n    }\n    /**\n     * Resets all stateful track informaion used during playback.\n     * @return {Track}\n     */\n\n\n    _createClass(Track, [{\n      key: \"reset\",\n      value: function reset() {\n        this.enabled = true;\n        this.eventIndex = 0;\n        this.pointer = 0;\n        this.lastTick = 0;\n        this.lastStatus = null;\n        this.delta = 0;\n        this.runningDelta = 0;\n        return this;\n      }\n      /**\n       * Sets this track to be enabled during playback.\n       * @return {Track}\n       */\n\n    }, {\n      key: \"enable\",\n      value: function enable() {\n        this.enabled = true;\n        return this;\n      }\n      /**\n       * Sets this track to be disabled during playback.\n       * @return {Track}\n       */\n\n    }, {\n      key: \"disable\",\n      value: function disable() {\n        this.enabled = false;\n        return this;\n      }\n      /**\n       * Sets the track event index to the nearest event to the given tick.\n       * @param {number} tick\n       * @return {Track}\n       */\n\n    }, {\n      key: \"setEventIndexByTick\",\n      value: function setEventIndexByTick(tick) {\n        tick = tick || 0;\n\n        for (var i in this.events) {\n          if (this.events[i].tick >= tick) {\n            this.eventIndex = i;\n            return this;\n          }\n        }\n      }\n      /**\n       * Gets byte located at pointer position.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getCurrentByte\",\n      value: function getCurrentByte() {\n        return this.data[this.pointer];\n      }\n      /**\n       * Gets count of delta bytes and current pointer position.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getDeltaByteCount\",\n      value: function getDeltaByteCount() {\n        // Get byte count of delta VLV\n        // http://www.ccarh.org/courses/253/handout/vlv/\n        // If byte is greater or equal to 80h (128 decimal) then the next byte\n        // is also part of the VLV,\n        // else byte is the last byte in a VLV.\n        var currentByte = this.getCurrentByte();\n        var byteCount = 1;\n\n        while (currentByte >= 128) {\n          currentByte = this.data[this.pointer + byteCount];\n          byteCount++;\n        }\n\n        return byteCount;\n      }\n      /**\n       * Get delta value at current pointer position.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getDelta\",\n      value: function getDelta() {\n        return Utils.readVarInt(this.data.subarray(this.pointer, this.pointer + this.getDeltaByteCount()));\n      }\n      /**\n       * Handles event within a given track starting at specified index\n       * @param {number} currentTick\n       * @param {boolean} dryRun - If true events will be parsed and returned regardless of time.\n       */\n\n    }, {\n      key: \"handleEvent\",\n      value: function handleEvent(currentTick, dryRun) {\n        dryRun = dryRun || false;\n\n        if (dryRun) {\n          var elapsedTicks = currentTick - this.lastTick;\n          var delta = this.getDelta();\n          var eventReady = elapsedTicks >= delta;\n\n          if (this.pointer < this.data.length && (dryRun || eventReady)) {\n            var _event = this.parseEvent();\n\n            if (this.enabled) return _event; // Recursively call this function for each event ahead that has 0 delta time?\n          }\n        } else {\n          // Let's actually play the MIDI from the generated JSON events created by the dry run.\n          if (this.events[this.eventIndex] && this.events[this.eventIndex].tick <= currentTick) {\n            this.eventIndex++;\n            if (this.enabled) return this.events[this.eventIndex - 1];\n          }\n        }\n\n        return null;\n      }\n      /**\n       * Get string data from event.\n       * @param {number} eventStartIndex\n       * @return {string}\n       */\n\n    }, {\n      key: \"getStringData\",\n      value: function getStringData(eventStartIndex) {\n        var currentByte = this.pointer;\n        var byteCount = 1;\n        var length = Utils.readVarInt(this.data.subarray(eventStartIndex + 2, eventStartIndex + 2 + byteCount));\n        return Utils.bytesToLetters(this.data.subarray(eventStartIndex + byteCount + 2, eventStartIndex + byteCount + length + 2));\n      }\n      /**\n       * Parses event into JSON and advances pointer for the track\n       * @return {object}\n       */\n\n    }, {\n      key: \"parseEvent\",\n      value: function parseEvent() {\n        var eventStartIndex = this.pointer + this.getDeltaByteCount();\n        var eventJson = {};\n        var deltaByteCount = this.getDeltaByteCount();\n        eventJson.track = this.index + 1;\n        eventJson.delta = this.getDelta();\n        this.lastTick = this.lastTick + eventJson.delta;\n        this.runningDelta += eventJson.delta;\n        eventJson.tick = this.runningDelta;\n        eventJson.byteIndex = this.pointer; //eventJson.raw = event;\n\n        if (this.data[eventStartIndex] == 0xff) {\n          // Meta Event\n          // If this is a meta event we should emit the data and immediately move to the next event\n          // otherwise if we let it run through the next cycle a slight delay will accumulate if multiple tracks\n          // are being played simultaneously\n          switch (this.data[eventStartIndex + 1]) {\n            case 0x00:\n              // Sequence Number\n              eventJson.name = 'Sequence Number';\n              break;\n\n            case 0x01:\n              // Text Event\n              eventJson.name = 'Text Event';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x02:\n              // Copyright Notice\n              eventJson.name = 'Copyright Notice';\n              break;\n\n            case 0x03:\n              // Sequence/Track Name\n              eventJson.name = 'Sequence/Track Name';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x04:\n              // Instrument Name\n              eventJson.name = 'Instrument Name';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x05:\n              // Lyric\n              eventJson.name = 'Lyric';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x06:\n              // Marker\n              eventJson.name = 'Marker';\n              break;\n\n            case 0x07:\n              // Cue Point\n              eventJson.name = 'Cue Point';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x09:\n              // Device Name\n              eventJson.name = 'Device Name';\n              eventJson.string = this.getStringData(eventStartIndex);\n              break;\n\n            case 0x20:\n              // MIDI Channel Prefix\n              eventJson.name = 'MIDI Channel Prefix';\n              break;\n\n            case 0x21:\n              // MIDI Port\n              eventJson.name = 'MIDI Port';\n              eventJson.data = Utils.bytesToNumber([this.data[eventStartIndex + 3]]);\n              break;\n\n            case 0x2F:\n              // End of Track\n              eventJson.name = 'End of Track';\n              break;\n\n            case 0x51:\n              // Set Tempo\n              eventJson.name = 'Set Tempo';\n              eventJson.data = Math.round(60000000 / Utils.bytesToNumber(this.data.subarray(eventStartIndex + 3, eventStartIndex + 6)));\n              this.tempo = eventJson.data;\n              break;\n\n            case 0x54:\n              // SMTPE Offset\n              eventJson.name = 'SMTPE Offset';\n              break;\n\n            case 0x58:\n              // Time Signature\n              // FF 58 04 nn dd cc bb\n              eventJson.name = 'Time Signature';\n              eventJson.data = this.data.subarray(eventStartIndex + 3, eventStartIndex + 7);\n              eventJson.timeSignature = \"\" + eventJson.data[0] + \"/\" + Math.pow(2, eventJson.data[1]);\n              break;\n\n            case 0x59:\n              // Key Signature\n              // FF 59 02 sf mi\n              eventJson.name = 'Key Signature';\n              eventJson.data = this.data.subarray(eventStartIndex + 3, eventStartIndex + 5);\n\n              if (eventJson.data[0] >= 0) {\n                eventJson.keySignature = Constants.CIRCLE_OF_FIFTHS[eventJson.data[0]];\n              } else if (eventJson.data[0] < 0) {\n                eventJson.keySignature = Constants.CIRCLE_OF_FOURTHS[Math.abs(eventJson.data[0])];\n              }\n\n              if (eventJson.data[1] == 0) {\n                eventJson.keySignature += \" Major\";\n              } else if (eventJson.data[1] == 1) {\n                eventJson.keySignature += \" Minor\";\n              }\n\n              break;\n\n            case 0x7F:\n              // Sequencer-Specific Meta-event\n              eventJson.name = 'Sequencer-Specific Meta-event';\n              break;\n\n            default:\n              eventJson.name = 'Unknown: ' + this.data[eventStartIndex + 1].toString(16);\n              break;\n          }\n\n          var length = this.data[this.pointer + deltaByteCount + 2]; // Some meta events will have vlv that needs to be handled\n\n          this.pointer += deltaByteCount + 3 + length;\n        } else if (this.data[eventStartIndex] == 0xf0) {\n          // Sysex\n          eventJson.name = 'Sysex';\n          var length = this.data[this.pointer + deltaByteCount + 1];\n          this.pointer += deltaByteCount + 2 + length;\n        } else {\n          // Voice event\n          if (this.data[eventStartIndex] < 0x80) {\n            // Running status\n            eventJson.running = true;\n            eventJson.noteNumber = this.data[eventStartIndex];\n            eventJson.noteName = Constants.NOTES[this.data[eventStartIndex]];\n            eventJson.velocity = this.data[eventStartIndex + 1];\n\n            if (this.lastStatus <= 0x8f) {\n              eventJson.name = 'Note off';\n              eventJson.channel = this.lastStatus - 0x80 + 1;\n            } else if (this.lastStatus <= 0x9f) {\n              eventJson.name = 'Note on';\n              eventJson.channel = this.lastStatus - 0x90 + 1;\n            }\n\n            this.pointer += deltaByteCount + 2;\n          } else {\n            this.lastStatus = this.data[eventStartIndex];\n\n            if (this.data[eventStartIndex] <= 0x8f) {\n              // Note off\n              eventJson.name = 'Note off';\n              eventJson.channel = this.lastStatus - 0x80 + 1;\n              eventJson.noteNumber = this.data[eventStartIndex + 1];\n              eventJson.noteName = Constants.NOTES[this.data[eventStartIndex + 1]];\n              eventJson.velocity = Math.round(this.data[eventStartIndex + 2] / 127 * 100);\n              this.pointer += deltaByteCount + 3;\n            } else if (this.data[eventStartIndex] <= 0x9f) {\n              // Note on\n              eventJson.name = 'Note on';\n              eventJson.channel = this.lastStatus - 0x90 + 1;\n              eventJson.noteNumber = this.data[eventStartIndex + 1];\n              eventJson.noteName = Constants.NOTES[this.data[eventStartIndex + 1]];\n              eventJson.velocity = Math.round(this.data[eventStartIndex + 2] / 127 * 100);\n              this.pointer += deltaByteCount + 3;\n            } else if (this.data[eventStartIndex] <= 0xaf) {\n              // Polyphonic Key Pressure\n              eventJson.name = 'Polyphonic Key Pressure';\n              eventJson.channel = this.lastStatus - 0xa0 + 1;\n              eventJson.note = Constants.NOTES[this.data[eventStartIndex + 1]];\n              eventJson.pressure = event[2];\n              this.pointer += deltaByteCount + 3;\n            } else if (this.data[eventStartIndex] <= 0xbf) {\n              // Controller Change\n              eventJson.name = 'Controller Change';\n              eventJson.channel = this.lastStatus - 0xb0 + 1;\n              eventJson.number = this.data[eventStartIndex + 1];\n              eventJson.value = this.data[eventStartIndex + 2];\n              this.pointer += deltaByteCount + 3;\n            } else if (this.data[eventStartIndex] <= 0xcf) {\n              // Program Change\n              eventJson.name = 'Program Change';\n              eventJson.channel = this.lastStatus - 0xc0 + 1;\n              eventJson.value = this.data[eventStartIndex + 1];\n              this.pointer += deltaByteCount + 2;\n            } else if (this.data[eventStartIndex] <= 0xdf) {\n              // Channel Key Pressure\n              eventJson.name = 'Channel Key Pressure';\n              eventJson.channel = this.lastStatus - 0xd0 + 1;\n              this.pointer += deltaByteCount + 2;\n            } else if (this.data[eventStartIndex] <= 0xef) {\n              // Pitch Bend\n              eventJson.name = 'Pitch Bend';\n              eventJson.channel = this.lastStatus - 0xe0 + 1;\n              this.pointer += deltaByteCount + 3;\n            } else {\n              eventJson.name = 'Unknown.  Pointer: ' + this.pointer.toString() + ' ' + eventStartIndex.toString() + ' ' + this.data.length;\n            }\n          }\n        }\n\n        this.delta += eventJson.delta;\n        this.events.push(eventJson);\n        return eventJson;\n      }\n      /**\n       * Returns true if pointer has reached the end of the track.\n       * @param {boolean}\n       */\n\n    }, {\n      key: \"endOfTrack\",\n      value: function endOfTrack() {\n        if (this.data[this.pointer + 1] == 0xff && this.data[this.pointer + 2] == 0x2f && this.data[this.pointer + 3] == 0x00) {\n          return true;\n        }\n\n        return false;\n      }\n    }]);\n\n    return Track;\n  }();\n\n  if (!Uint8Array.prototype.forEach) {\n    Object.defineProperty(Uint8Array.prototype, 'forEach', {\n      value: Array.prototype.forEach\n    });\n  }\n  /**\n   * Main player class.  Contains methods to load files, start, stop.\n   * @param {function} - Callback to fire for each MIDI event.  Can also be added with on('midiEvent', fn)\n   * @param {array} - Array buffer of MIDI file (optional).\n   */\n\n\n  var Player = /*#__PURE__*/function () {\n    function Player(eventHandler, buffer) {\n      _classCallCheck(this, Player);\n\n      this.sampleRate = 5; // milliseconds\n\n      this.startTime = 0;\n      this.buffer = buffer || null;\n      this.division;\n      this.format;\n      this.setIntervalId = false;\n      this.tracks = [];\n      this.instruments = [];\n      this.defaultTempo = 120;\n      this.tempo = null;\n      this.startTick = 0;\n      this.tick = 0;\n      this.lastTick = null;\n      this.inLoop = false;\n      this.totalTicks = 0;\n      this.events = [];\n      this.totalEvents = 0;\n      this.eventListeners = {};\n      if (typeof eventHandler === 'function') this.on('midiEvent', eventHandler);\n    }\n    /**\n     * Load a file into the player (Node.js only).\n     * @param {string} path - Path of file.\n     * @return {Player}\n     */\n\n\n    _createClass(Player, [{\n      key: \"loadFile\",\n      value: function loadFile(path) {\n        var fs = require('fs');\n\n        this.buffer = fs.readFileSync(path);\n        return this.fileLoaded();\n      }\n      /**\n       * Load an array buffer into the player.\n       * @param {array} arrayBuffer - Array buffer of file to be loaded.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"loadArrayBuffer\",\n      value: function loadArrayBuffer(arrayBuffer) {\n        this.buffer = new Uint8Array(arrayBuffer);\n        return this.fileLoaded();\n      }\n      /**\n       * Load a data URI into the player.\n       * @param {string} dataUri - Data URI to be loaded.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"loadDataUri\",\n      value: function loadDataUri(dataUri) {\n        // convert base64 to raw binary data held in a string.\n        // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this\n        var byteString = Utils.atob(dataUri.split(',')[1]); // write the bytes of the string to an ArrayBuffer\n\n        var ia = new Uint8Array(byteString.length);\n\n        for (var i = 0; i < byteString.length; i++) {\n          ia[i] = byteString.charCodeAt(i);\n        }\n\n        this.buffer = ia;\n        return this.fileLoaded();\n      }\n      /**\n       * Get filesize of loaded file in number of bytes.\n       * @return {number} - The filesize.\n       */\n\n    }, {\n      key: \"getFilesize\",\n      value: function getFilesize() {\n        return this.buffer ? this.buffer.length : 0;\n      }\n      /**\n       * Sets default tempo, parses file for necessary information, and does a dry run to calculate total length.\n       * Populates this.events & this.totalTicks.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"fileLoaded\",\n      value: function fileLoaded() {\n        if (!this.validate()) throw 'Invalid MIDI file; should start with MThd';\n        return this.setTempo(this.defaultTempo).getDivision().getFormat().getTracks().dryRun();\n      }\n      /**\n       * Validates file using simple means - first four bytes should == MThd.\n       * @return {boolean}\n       */\n\n    }, {\n      key: \"validate\",\n      value: function validate() {\n        return Utils.bytesToLetters(this.buffer.subarray(0, 4)) === 'MThd';\n      }\n      /**\n       * Gets MIDI file format for loaded file.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"getFormat\",\n      value: function getFormat() {\n        /*\n        MIDI files come in 3 variations:\n        Format 0 which contain a single track\n        Format 1 which contain one or more simultaneous tracks\n        (ie all tracks are to be played simultaneously).\n        Format 2 which contain one or more independant tracks\n        (ie each track is to be played independantly of the others).\n        return Utils.bytesToNumber(this.buffer.subarray(8, 10));\n        */\n        this.format = Utils.bytesToNumber(this.buffer.subarray(8, 10));\n        return this;\n      }\n      /**\n       * Parses out tracks, places them in this.tracks and initializes this.pointers\n       * @return {Player}\n       */\n\n    }, {\n      key: \"getTracks\",\n      value: function getTracks() {\n        this.tracks = [];\n        var trackOffset = 0;\n\n        while (trackOffset < this.buffer.length) {\n          if (Utils.bytesToLetters(this.buffer.subarray(trackOffset, trackOffset + 4)) == 'MTrk') {\n            var trackLength = Utils.bytesToNumber(this.buffer.subarray(trackOffset + 4, trackOffset + 8));\n            this.tracks.push(new Track(this.tracks.length, this.buffer.subarray(trackOffset + 8, trackOffset + 8 + trackLength)));\n          }\n\n          trackOffset += Utils.bytesToNumber(this.buffer.subarray(trackOffset + 4, trackOffset + 8)) + 8;\n        }\n\n        return this;\n      }\n      /**\n       * Enables a track for playing.\n       * @param {number} trackNumber - Track number\n       * @return {Player}\n       */\n\n    }, {\n      key: \"enableTrack\",\n      value: function enableTrack(trackNumber) {\n        this.tracks[trackNumber - 1].enable();\n        return this;\n      }\n      /**\n       * Disables a track for playing.\n       * @param {number} - Track number\n       * @return {Player}\n       */\n\n    }, {\n      key: \"disableTrack\",\n      value: function disableTrack(trackNumber) {\n        this.tracks[trackNumber - 1].disable();\n        return this;\n      }\n      /**\n       * Gets quarter note division of loaded MIDI file.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"getDivision\",\n      value: function getDivision() {\n        this.division = Utils.bytesToNumber(this.buffer.subarray(12, 14));\n        return this;\n      }\n      /**\n       * The main play loop.\n       * @param {boolean} - Indicates whether or not this is being called simply for parsing purposes.  Disregards timing if so.\n       * @return {undefined}\n       */\n\n    }, {\n      key: \"playLoop\",\n      value: function playLoop(dryRun) {\n        if (!this.inLoop) {\n          this.inLoop = true;\n          this.tick = this.getCurrentTick();\n          this.tracks.forEach(function (track) {\n            // Handle next event\n            if (!dryRun && this.endOfFile()) {\n              //console.log('end of file')\n              this.triggerPlayerEvent('endOfFile');\n              this.stop();\n            } else {\n              var event = track.handleEvent(this.tick, dryRun);\n\n              if (dryRun && event) {\n                if (event.hasOwnProperty('name') && event.name === 'Set Tempo') {\n                  // Grab tempo if available.\n                  this.defaultTempo = event.data;\n                  this.setTempo(event.data);\n                }\n\n                if (event.hasOwnProperty('name') && event.name === 'Program Change') {\n                  if (!this.instruments.includes(event.value)) {\n                    this.instruments.push(event.value);\n                  }\n                }\n              } else if (event) this.emitEvent(event);\n            }\n          }, this);\n          if (!dryRun) this.triggerPlayerEvent('playing', {\n            tick: this.tick\n          });\n          this.inLoop = false;\n        }\n      }\n      /**\n       * Setter for tempo.\n       * @param {number} - Tempo in bpm (defaults to 120)\n       */\n\n    }, {\n      key: \"setTempo\",\n      value: function setTempo(tempo) {\n        this.tempo = tempo;\n        return this;\n      }\n      /**\n       * Setter for startTime.\n       * @param {number} - UTC timestamp\n       */\n\n    }, {\n      key: \"setStartTime\",\n      value: function setStartTime(startTime) {\n        this.startTime = startTime;\n      }\n      /**\n       * Start playing loaded MIDI file if not already playing.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"play\",\n      value: function play() {\n        if (this.isPlaying()) throw 'Already playing...'; // Initialize\n\n        if (!this.startTime) this.startTime = new Date().getTime(); // Start play loop\n        //window.requestAnimationFrame(this.playLoop.bind(this));\n\n        this.setIntervalId = setInterval(this.playLoop.bind(this), this.sampleRate);\n        return this;\n      }\n      /**\n       * Pauses playback if playing.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"pause\",\n      value: function pause() {\n        clearInterval(this.setIntervalId);\n        this.setIntervalId = false;\n        this.startTick = this.tick;\n        this.startTime = 0;\n        return this;\n      }\n      /**\n       * Stops playback if playing.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"stop\",\n      value: function stop() {\n        clearInterval(this.setIntervalId);\n        this.setIntervalId = false;\n        this.startTick = 0;\n        this.startTime = 0;\n        this.resetTracks();\n        return this;\n      }\n      /**\n       * Skips player pointer to specified tick.\n       * @param {number} - Tick to skip to.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"skipToTick\",\n      value: function skipToTick(tick) {\n        this.stop();\n        this.startTick = tick; // Need to set track event indexes to the nearest possible event to the specified tick.\n\n        this.tracks.forEach(function (track) {\n          track.setEventIndexByTick(tick);\n        });\n        return this;\n      }\n      /**\n       * Skips player pointer to specified percentage.\n       * @param {number} - Percent value in integer format.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"skipToPercent\",\n      value: function skipToPercent(percent) {\n        if (percent < 0 || percent > 100) throw \"Percent must be number between 1 and 100.\";\n        this.skipToTick(Math.round(percent / 100 * this.totalTicks));\n        return this;\n      }\n      /**\n       * Skips player pointer to specified seconds.\n       * @param {number} - Seconds to skip to.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"skipToSeconds\",\n      value: function skipToSeconds(seconds) {\n        var songTime = this.getSongTime();\n        if (seconds < 0 || seconds > songTime) throw seconds + \" seconds not within song time of \" + songTime;\n        this.skipToPercent(seconds / songTime * 100);\n        return this;\n      }\n      /**\n       * Checks if player is playing\n       * @return {boolean}\n       */\n\n    }, {\n      key: \"isPlaying\",\n      value: function isPlaying() {\n        return this.setIntervalId > 0 || _typeof(this.setIntervalId) === 'object';\n      }\n      /**\n       * Plays the loaded MIDI file without regard for timing and saves events in this.events.  Essentially used as a parser.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"dryRun\",\n      value: function dryRun() {\n        // Reset tracks first\n        this.resetTracks();\n\n        while (!this.endOfFile()) {\n          this.playLoop(true);\n        }\n\n        this.events = this.getEvents();\n        this.totalEvents = this.getTotalEvents();\n        this.totalTicks = this.getTotalTicks();\n        this.startTick = 0;\n        this.startTime = 0; // Leave tracks in pristine condish\n\n        this.resetTracks(); //console.log('Song time: ' + this.getSongTime() + ' seconds / ' + this.totalTicks + ' ticks.');\n\n        this.triggerPlayerEvent('fileLoaded', this);\n        return this;\n      }\n      /**\n       * Resets play pointers for all tracks.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"resetTracks\",\n      value: function resetTracks() {\n        this.tracks.forEach(function (track) {\n          return track.reset();\n        });\n        return this;\n      }\n      /**\n       * Gets an array of events grouped by track.\n       * @return {array}\n       */\n\n    }, {\n      key: \"getEvents\",\n      value: function getEvents() {\n        return this.tracks.map(function (track) {\n          return track.events;\n        });\n      }\n      /**\n       * Gets total number of ticks in the loaded MIDI file.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getTotalTicks\",\n      value: function getTotalTicks() {\n        return Math.max.apply(null, this.tracks.map(function (track) {\n          return track.delta;\n        }));\n      }\n      /**\n       * Gets total number of events in the loaded MIDI file.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getTotalEvents\",\n      value: function getTotalEvents() {\n        return this.tracks.reduce(function (a, b) {\n          return {\n            events: {\n              length: a.events.length + b.events.length\n            }\n          };\n        }, {\n          events: {\n            length: 0\n          }\n        }).events.length;\n      }\n      /**\n       * Gets song duration in seconds.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getSongTime\",\n      value: function getSongTime() {\n        return this.totalTicks / this.division / this.tempo * 60;\n      }\n      /**\n       * Gets remaining number of seconds in playback.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getSongTimeRemaining\",\n      value: function getSongTimeRemaining() {\n        return Math.round((this.totalTicks - this.getCurrentTick()) / this.division / this.tempo * 60);\n      }\n      /**\n       * Gets remaining percent of playback.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getSongPercentRemaining\",\n      value: function getSongPercentRemaining() {\n        return Math.round(this.getSongTimeRemaining() / this.getSongTime() * 100);\n      }\n      /**\n       * Number of bytes processed in the loaded MIDI file.\n       * @return {number}\n       */\n\n    }, {\n      key: \"bytesProcessed\",\n      value: function bytesProcessed() {\n        // Currently assume header chunk is strictly 14 bytes\n        return 14 + this.tracks.length * 8 + this.tracks.reduce(function (a, b) {\n          return {\n            pointer: a.pointer + b.pointer\n          };\n        }, {\n          pointer: 0\n        }).pointer;\n      }\n      /**\n       * Number of events played up to this point.\n       * @return {number}\n       */\n\n    }, {\n      key: \"eventsPlayed\",\n      value: function eventsPlayed() {\n        return this.tracks.reduce(function (a, b) {\n          return {\n            eventIndex: a.eventIndex + b.eventIndex\n          };\n        }, {\n          eventIndex: 0\n        }).eventIndex;\n      }\n      /**\n       * Determines if the player pointer has reached the end of the loaded MIDI file.\n       * Used in two ways:\n       * 1. If playing result is based on loaded JSON events.\n       * 2. If parsing (dryRun) it's based on the actual buffer length vs bytes processed.\n       * @return {boolean}\n       */\n\n    }, {\n      key: \"endOfFile\",\n      value: function endOfFile() {\n        if (this.isPlaying()) {\n          return this.totalTicks - this.tick <= 0;\n        }\n\n        return this.bytesProcessed() >= this.buffer.length;\n      }\n      /**\n       * Gets the current tick number in playback.\n       * @return {number}\n       */\n\n    }, {\n      key: \"getCurrentTick\",\n      value: function getCurrentTick() {\n        if (!this.startTime && this.tick) return this.startTick;else if (!this.startTime) return 0;\n        return Math.round((new Date().getTime() - this.startTime) / 1000 * (this.division * (this.tempo / 60))) + this.startTick;\n      }\n      /**\n       * Sends MIDI event out to listener.\n       * @param {object}\n       * @return {Player}\n       */\n\n    }, {\n      key: \"emitEvent\",\n      value: function emitEvent(event) {\n        this.triggerPlayerEvent('midiEvent', event);\n        return this;\n      }\n      /**\n       * Subscribes events to listeners\n       * @param {string} - Name of event to subscribe to.\n       * @param {function} - Callback to fire when event is broadcast.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"on\",\n      value: function on(playerEvent, fn) {\n        if (!this.eventListeners.hasOwnProperty(playerEvent)) this.eventListeners[playerEvent] = [];\n        this.eventListeners[playerEvent].push(fn);\n        return this;\n      }\n      /**\n       * Broadcasts event to trigger subscribed callbacks.\n       * @param {string} - Name of event.\n       * @param {object} - Data to be passed to subscriber callback.\n       * @return {Player}\n       */\n\n    }, {\n      key: \"triggerPlayerEvent\",\n      value: function triggerPlayerEvent(playerEvent, data) {\n        if (this.eventListeners.hasOwnProperty(playerEvent)) this.eventListeners[playerEvent].forEach(function (fn) {\n          return fn(data || {});\n        });\n        return this;\n      }\n    }]);\n\n    return Player;\n  }();\n\n  var index = {\n    Player: Player,\n    Utils: Utils,\n    Constants: Constants\n  };\n\n  return index;\n\n}());\n"]}