{"version":3,"file":"js/766-439e5d8a93a3f2dcd61e.chunk.js","mappings":"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","sources":["webpack://app/./node_modules/howler/dist/howler.js"],"sourcesContent":["/*!\n *  howler.js v2.2.3\n *  howlerjs.com\n *\n *  (c) 2013-2020, James Simpson of GoldFire Studios\n *  goldfirestudios.com\n *\n *  MIT License\n */\n\n(function() {\n\n  'use strict';\n\n  /** Global Methods **/\n  /***************************************************************************/\n\n  /**\n   * Create the global controller. All contained methods and properties apply\n   * to all sounds that are currently playing or will be in the future.\n   */\n  var HowlerGlobal = function() {\n    this.init();\n  };\n  HowlerGlobal.prototype = {\n    /**\n     * Initialize the global Howler object.\n     * @return {Howler}\n     */\n    init: function() {\n      var self = this || Howler;\n\n      // Create a global ID counter.\n      self._counter = 1000;\n\n      // Pool of unlocked HTML5 Audio objects.\n      self._html5AudioPool = [];\n      self.html5PoolSize = 10;\n\n      // Internal properties.\n      self._codecs = {};\n      self._howls = [];\n      self._muted = false;\n      self._volume = 1;\n      self._canPlayEvent = 'canplaythrough';\n      self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;\n\n      // Public properties.\n      self.masterGain = null;\n      self.noAudio = false;\n      self.usingWebAudio = true;\n      self.autoSuspend = true;\n      self.ctx = null;\n\n      // Set to false to disable the auto audio unlocker.\n      self.autoUnlock = true;\n\n      // Setup the various state values for global tracking.\n      self._setup();\n\n      return self;\n    },\n\n    /**\n     * Get/set the global volume for all sounds.\n     * @param  {Float} vol Volume from 0.0 to 1.0.\n     * @return {Howler/Float}     Returns self or current volume.\n     */\n    volume: function(vol) {\n      var self = this || Howler;\n      vol = parseFloat(vol);\n\n      // If we don't have an AudioContext created yet, run the setup.\n      if (!self.ctx) {\n        setupAudioContext();\n      }\n\n      if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n        self._volume = vol;\n\n        // Don't update any of the nodes if we are muted.\n        if (self._muted) {\n          return self;\n        }\n\n        // When using Web Audio, we just need to adjust the master gain.\n        if (self.usingWebAudio) {\n          self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n        }\n\n        // Loop through and change volume for all HTML5 audio nodes.\n        for (var i=0; i<self._howls.length; i++) {\n          if (!self._howls[i]._webAudio) {\n            // Get all of the sounds in this Howl group.\n            var ids = self._howls[i]._getSoundIds();\n\n            // Loop through all sounds and change the volumes.\n            for (var j=0; j<ids.length; j++) {\n              var sound = self._howls[i]._soundById(ids[j]);\n\n              if (sound && sound._node) {\n                sound._node.volume = sound._volume * vol;\n              }\n            }\n          }\n        }\n\n        return self;\n      }\n\n      return self._volume;\n    },\n\n    /**\n     * Handle muting and unmuting globally.\n     * @param  {Boolean} muted Is muted or not.\n     */\n    mute: function(muted) {\n      var self = this || Howler;\n\n      // If we don't have an AudioContext created yet, run the setup.\n      if (!self.ctx) {\n        setupAudioContext();\n      }\n\n      self._muted = muted;\n\n      // With Web Audio, we just need to mute the master gain.\n      if (self.usingWebAudio) {\n        self.masterGain.gain.setValueAtTime(muted ? 0 : self._volume, Howler.ctx.currentTime);\n      }\n\n      // Loop through and mute all HTML5 Audio nodes.\n      for (var i=0; i<self._howls.length; i++) {\n        if (!self._howls[i]._webAudio) {\n          // Get all of the sounds in this Howl group.\n          var ids = self._howls[i]._getSoundIds();\n\n          // Loop through all sounds and mark the audio node as muted.\n          for (var j=0; j<ids.length; j++) {\n            var sound = self._howls[i]._soundById(ids[j]);\n\n            if (sound && sound._node) {\n              sound._node.muted = (muted) ? true : sound._muted;\n            }\n          }\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Handle stopping all sounds globally.\n     */\n    stop: function() {\n      var self = this || Howler;\n\n      // Loop through all Howls and stop them.\n      for (var i=0; i<self._howls.length; i++) {\n        self._howls[i].stop();\n      }\n\n      return self;\n    },\n\n    /**\n     * Unload and destroy all currently loaded Howl objects.\n     * @return {Howler}\n     */\n    unload: function() {\n      var self = this || Howler;\n\n      for (var i=self._howls.length-1; i>=0; i--) {\n        self._howls[i].unload();\n      }\n\n      // Create a new AudioContext to make sure it is fully reset.\n      if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') {\n        self.ctx.close();\n        self.ctx = null;\n        setupAudioContext();\n      }\n\n      return self;\n    },\n\n    /**\n     * Check for codec support of specific extension.\n     * @param  {String} ext Audio file extention.\n     * @return {Boolean}\n     */\n    codecs: function(ext) {\n      return (this || Howler)._codecs[ext.replace(/^x-/, '')];\n    },\n\n    /**\n     * Setup various state values for global tracking.\n     * @return {Howler}\n     */\n    _setup: function() {\n      var self = this || Howler;\n\n      // Keeps track of the suspend/resume state of the AudioContext.\n      self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended';\n\n      // Automatically begin the 30-second suspend process\n      self._autoSuspend();\n\n      // Check if audio is available.\n      if (!self.usingWebAudio) {\n        // No audio is available on this system if noAudio is set to true.\n        if (typeof Audio !== 'undefined') {\n          try {\n            var test = new Audio();\n\n            // Check if the canplaythrough event is available.\n            if (typeof test.oncanplaythrough === 'undefined') {\n              self._canPlayEvent = 'canplay';\n            }\n          } catch(e) {\n            self.noAudio = true;\n          }\n        } else {\n          self.noAudio = true;\n        }\n      }\n\n      // Test to make sure audio isn't disabled in Internet Explorer.\n      try {\n        var test = new Audio();\n        if (test.muted) {\n          self.noAudio = true;\n        }\n      } catch (e) {}\n\n      // Check for supported codecs.\n      if (!self.noAudio) {\n        self._setupCodecs();\n      }\n\n      return self;\n    },\n\n    /**\n     * Check for browser support for various codecs and cache the results.\n     * @return {Howler}\n     */\n    _setupCodecs: function() {\n      var self = this || Howler;\n      var audioTest = null;\n\n      // Must wrap in a try/catch because IE11 in server mode throws an error.\n      try {\n        audioTest = (typeof Audio !== 'undefined') ? new Audio() : null;\n      } catch (err) {\n        return self;\n      }\n\n      if (!audioTest || typeof audioTest.canPlayType !== 'function') {\n        return self;\n      }\n\n      var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, '');\n\n      // Opera version <33 has mixed MP3 support, so we need to check for and block it.\n      var ua = self._navigator ? self._navigator.userAgent : '';\n      var checkOpera = ua.match(/OPR\\/([0-6].)/g);\n      var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);\n      var checkSafari = ua.indexOf('Safari') !== -1 && ua.indexOf('Chrome') === -1;\n      var safariVersion = ua.match(/Version\\/(.*?) /);\n      var isOldSafari = (checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15);\n\n      self._codecs = {\n        mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))),\n        mpeg: !!mpegTest,\n        opus: !!audioTest.canPlayType('audio/ogg; codecs=\"opus\"').replace(/^no$/, ''),\n        ogg: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n        oga: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n        wav: !!(audioTest.canPlayType('audio/wav; codecs=\"1\"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''),\n        aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),\n        caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),\n        m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n        m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n        mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n        weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n        webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n        dolby: !!audioTest.canPlayType('audio/mp4; codecs=\"ec-3\"').replace(/^no$/, ''),\n        flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '')\n      };\n\n      return self;\n    },\n\n    /**\n     * Some browsers/devices will only allow audio to be played after a user interaction.\n     * Attempt to automatically unlock audio on the first user interaction.\n     * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/\n     * @return {Howler}\n     */\n    _unlockAudio: function() {\n      var self = this || Howler;\n\n      // Only run this if Web Audio is supported and it hasn't already been unlocked.\n      if (self._audioUnlocked || !self.ctx) {\n        return;\n      }\n\n      self._audioUnlocked = false;\n      self.autoUnlock = false;\n\n      // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.\n      // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.\n      // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate.\n      if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {\n        self._mobileUnloaded = true;\n        self.unload();\n      }\n\n      // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per:\n      // http://stackoverflow.com/questions/24119684\n      self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);\n\n      // Call this method on touch start to create and play a buffer,\n      // then check if the audio actually played to determine if\n      // audio has now been unlocked on iOS, Android, etc.\n      var unlock = function(e) {\n        // Create a pool of unlocked HTML5 Audio objects that can\n        // be used for playing sounds without user interaction. HTML5\n        // Audio objects must be individually unlocked, as opposed\n        // to the WebAudio API which only needs a single activation.\n        // This must occur before WebAudio setup or the source.onended\n        // event will not fire.\n        while (self._html5AudioPool.length < self.html5PoolSize) {\n          try {\n            var audioNode = new Audio();\n\n            // Mark this Audio object as unlocked to ensure it can get returned\n            // to the unlocked pool when released.\n            audioNode._unlocked = true;\n\n            // Add the audio node to the pool.\n            self._releaseHtml5Audio(audioNode);\n          } catch (e) {\n            self.noAudio = true;\n            break;\n          }\n        }\n\n        // Loop through any assigned audio nodes and unlock them.\n        for (var i=0; i<self._howls.length; i++) {\n          if (!self._howls[i]._webAudio) {\n            // Get all of the sounds in this Howl group.\n            var ids = self._howls[i]._getSoundIds();\n\n            // Loop through all sounds and unlock the audio nodes.\n            for (var j=0; j<ids.length; j++) {\n              var sound = self._howls[i]._soundById(ids[j]);\n\n              if (sound && sound._node && !sound._node._unlocked) {\n                sound._node._unlocked = true;\n                sound._node.load();\n              }\n            }\n          }\n        }\n\n        // Fix Android can not play in suspend state.\n        self._autoResume();\n\n        // Create an empty buffer.\n        var source = self.ctx.createBufferSource();\n        source.buffer = self._scratchBuffer;\n        source.connect(self.ctx.destination);\n\n        // Play the empty buffer.\n        if (typeof source.start === 'undefined') {\n          source.noteOn(0);\n        } else {\n          source.start(0);\n        }\n\n        // Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55.\n        if (typeof self.ctx.resume === 'function') {\n          self.ctx.resume();\n        }\n\n        // Setup a timeout to check that we are unlocked on the next event loop.\n        source.onended = function() {\n          source.disconnect(0);\n\n          // Update the unlocked state and prevent this check from happening again.\n          self._audioUnlocked = true;\n\n          // Remove the touch start listener.\n          document.removeEventListener('touchstart', unlock, true);\n          document.removeEventListener('touchend', unlock, true);\n          document.removeEventListener('click', unlock, true);\n          document.removeEventListener('keydown', unlock, true);\n\n          // Let all sounds know that audio has been unlocked.\n          for (var i=0; i<self._howls.length; i++) {\n            self._howls[i]._emit('unlock');\n          }\n        };\n      };\n\n      // Setup a touch start listener to attempt an unlock in.\n      document.addEventListener('touchstart', unlock, true);\n      document.addEventListener('touchend', unlock, true);\n      document.addEventListener('click', unlock, true);\n      document.addEventListener('keydown', unlock, true);\n\n      return self;\n    },\n\n    /**\n     * Get an unlocked HTML5 Audio object from the pool. If none are left,\n     * return a new Audio object and throw a warning.\n     * @return {Audio} HTML5 Audio object.\n     */\n    _obtainHtml5Audio: function() {\n      var self = this || Howler;\n\n      // Return the next object from the pool if one exists.\n      if (self._html5AudioPool.length) {\n        return self._html5AudioPool.pop();\n      }\n\n      //.Check if the audio is locked and throw a warning.\n      var testPlay = new Audio().play();\n      if (testPlay && typeof Promise !== 'undefined' && (testPlay instanceof Promise || typeof testPlay.then === 'function')) {\n        testPlay.catch(function() {\n          console.warn('HTML5 Audio pool exhausted, returning potentially locked audio object.');\n        });\n      }\n\n      return new Audio();\n    },\n\n    /**\n     * Return an activated HTML5 Audio object to the pool.\n     * @return {Howler}\n     */\n    _releaseHtml5Audio: function(audio) {\n      var self = this || Howler;\n\n      // Don't add audio to the pool if we don't know if it has been unlocked.\n      if (audio._unlocked) {\n        self._html5AudioPool.push(audio);\n      }\n\n      return self;\n    },\n\n    /**\n     * Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds.\n     * This saves processing/energy and fixes various browser-specific bugs with audio getting stuck.\n     * @return {Howler}\n     */\n    _autoSuspend: function() {\n      var self = this;\n\n      if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === 'undefined' || !Howler.usingWebAudio) {\n        return;\n      }\n\n      // Check if any sounds are playing.\n      for (var i=0; i<self._howls.length; i++) {\n        if (self._howls[i]._webAudio) {\n          for (var j=0; j<self._howls[i]._sounds.length; j++) {\n            if (!self._howls[i]._sounds[j]._paused) {\n              return self;\n            }\n          }\n        }\n      }\n\n      if (self._suspendTimer) {\n        clearTimeout(self._suspendTimer);\n      }\n\n      // If no sound has played after 30 seconds, suspend the context.\n      self._suspendTimer = setTimeout(function() {\n        if (!self.autoSuspend) {\n          return;\n        }\n\n        self._suspendTimer = null;\n        self.state = 'suspending';\n\n        // Handle updating the state of the audio context after suspending.\n        var handleSuspension = function() {\n          self.state = 'suspended';\n\n          if (self._resumeAfterSuspend) {\n            delete self._resumeAfterSuspend;\n            self._autoResume();\n          }\n        };\n\n        // Either the state gets suspended or it is interrupted.\n        // Either way, we need to update the state to suspended.\n        self.ctx.suspend().then(handleSuspension, handleSuspension);\n      }, 30000);\n\n      return self;\n    },\n\n    /**\n     * Automatically resume the Web Audio AudioContext when a new sound is played.\n     * @return {Howler}\n     */\n    _autoResume: function() {\n      var self = this;\n\n      if (!self.ctx || typeof self.ctx.resume === 'undefined' || !Howler.usingWebAudio) {\n        return;\n      }\n\n      if (self.state === 'running' && self.ctx.state !== 'interrupted' && self._suspendTimer) {\n        clearTimeout(self._suspendTimer);\n        self._suspendTimer = null;\n      } else if (self.state === 'suspended' || self.state === 'running' && self.ctx.state === 'interrupted') {\n        self.ctx.resume().then(function() {\n          self.state = 'running';\n\n          // Emit to all Howls that the audio has resumed.\n          for (var i=0; i<self._howls.length; i++) {\n            self._howls[i]._emit('resume');\n          }\n        });\n\n        if (self._suspendTimer) {\n          clearTimeout(self._suspendTimer);\n          self._suspendTimer = null;\n        }\n      } else if (self.state === 'suspending') {\n        self._resumeAfterSuspend = true;\n      }\n\n      return self;\n    }\n  };\n\n  // Setup the global audio controller.\n  var Howler = new HowlerGlobal();\n\n  /** Group Methods **/\n  /***************************************************************************/\n\n  /**\n   * Create an audio group controller.\n   * @param {Object} o Passed in properties for this group.\n   */\n  var Howl = function(o) {\n    var self = this;\n\n    // Throw an error if no source is provided.\n    if (!o.src || o.src.length === 0) {\n      console.error('An array of source files must be passed with any new Howl.');\n      return;\n    }\n\n    self.init(o);\n  };\n  Howl.prototype = {\n    /**\n     * Initialize a new Howl group object.\n     * @param  {Object} o Passed in properties for this group.\n     * @return {Howl}\n     */\n    init: function(o) {\n      var self = this;\n\n      // If we don't have an AudioContext created yet, run the setup.\n      if (!Howler.ctx) {\n        setupAudioContext();\n      }\n\n      // Setup user-defined default properties.\n      self._autoplay = o.autoplay || false;\n      self._format = (typeof o.format !== 'string') ? o.format : [o.format];\n      self._html5 = o.html5 || false;\n      self._muted = o.mute || false;\n      self._loop = o.loop || false;\n      self._pool = o.pool || 5;\n      self._preload = (typeof o.preload === 'boolean' || o.preload === 'metadata') ? o.preload : true;\n      self._rate = o.rate || 1;\n      self._sprite = o.sprite || {};\n      self._src = (typeof o.src !== 'string') ? o.src : [o.src];\n      self._volume = o.volume !== undefined ? o.volume : 1;\n      self._xhr = {\n        method: o.xhr && o.xhr.method ? o.xhr.method : 'GET',\n        headers: o.xhr && o.xhr.headers ? o.xhr.headers : null,\n        withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false,\n      };\n\n      // Setup all other default properties.\n      self._duration = 0;\n      self._state = 'unloaded';\n      self._sounds = [];\n      self._endTimers = {};\n      self._queue = [];\n      self._playLock = false;\n\n      // Setup event listeners.\n      self._onend = o.onend ? [{fn: o.onend}] : [];\n      self._onfade = o.onfade ? [{fn: o.onfade}] : [];\n      self._onload = o.onload ? [{fn: o.onload}] : [];\n      self._onloaderror = o.onloaderror ? [{fn: o.onloaderror}] : [];\n      self._onplayerror = o.onplayerror ? [{fn: o.onplayerror}] : [];\n      self._onpause = o.onpause ? [{fn: o.onpause}] : [];\n      self._onplay = o.onplay ? [{fn: o.onplay}] : [];\n      self._onstop = o.onstop ? [{fn: o.onstop}] : [];\n      self._onmute = o.onmute ? [{fn: o.onmute}] : [];\n      self._onvolume = o.onvolume ? [{fn: o.onvolume}] : [];\n      self._onrate = o.onrate ? [{fn: o.onrate}] : [];\n      self._onseek = o.onseek ? [{fn: o.onseek}] : [];\n      self._onunlock = o.onunlock ? [{fn: o.onunlock}] : [];\n      self._onresume = [];\n\n      // Web Audio or HTML5 Audio?\n      self._webAudio = Howler.usingWebAudio && !self._html5;\n\n      // Automatically try to enable audio.\n      if (typeof Howler.ctx !== 'undefined' && Howler.ctx && Howler.autoUnlock) {\n        Howler._unlockAudio();\n      }\n\n      // Keep track of this Howl group in the global controller.\n      Howler._howls.push(self);\n\n      // If they selected autoplay, add a play event to the load queue.\n      if (self._autoplay) {\n        self._queue.push({\n          event: 'play',\n          action: function() {\n            self.play();\n          }\n        });\n      }\n\n      // Load the source file unless otherwise specified.\n      if (self._preload && self._preload !== 'none') {\n        self.load();\n      }\n\n      return self;\n    },\n\n    /**\n     * Load the audio file.\n     * @return {Howler}\n     */\n    load: function() {\n      var self = this;\n      var url = null;\n\n      // If no audio is available, quit immediately.\n      if (Howler.noAudio) {\n        self._emit('loaderror', null, 'No audio support.');\n        return;\n      }\n\n      // Make sure our source is in an array.\n      if (typeof self._src === 'string') {\n        self._src = [self._src];\n      }\n\n      // Loop through the sources and pick the first one that is compatible.\n      for (var i=0; i<self._src.length; i++) {\n        var ext, str;\n\n        if (self._format && self._format[i]) {\n          // If an extension was specified, use that instead.\n          ext = self._format[i];\n        } else {\n          // Make sure the source is a string.\n          str = self._src[i];\n          if (typeof str !== 'string') {\n            self._emit('loaderror', null, 'Non-string found in selected audio sources - ignoring.');\n            continue;\n          }\n\n          // Extract the file extension from the URL or base64 data URI.\n          ext = /^data:audio\\/([^;,]+);/i.exec(str);\n          if (!ext) {\n            ext = /\\.([^.]+)$/.exec(str.split('?', 1)[0]);\n          }\n\n          if (ext) {\n            ext = ext[1].toLowerCase();\n          }\n        }\n\n        // Log a warning if no extension was found.\n        if (!ext) {\n          console.warn('No file extension was found. Consider using the \"format\" property or specify an extension.');\n        }\n\n        // Check if this extension is available.\n        if (ext && Howler.codecs(ext)) {\n          url = self._src[i];\n          break;\n        }\n      }\n\n      if (!url) {\n        self._emit('loaderror', null, 'No codec support for selected audio sources.');\n        return;\n      }\n\n      self._src = url;\n      self._state = 'loading';\n\n      // If the hosting page is HTTPS and the source isn't,\n      // drop down to HTML5 Audio to avoid Mixed Content errors.\n      if (window.location.protocol === 'https:' && url.slice(0, 5) === 'http:') {\n        self._html5 = true;\n        self._webAudio = false;\n      }\n\n      // Create a new sound object and add it to the pool.\n      new Sound(self);\n\n      // Load and decode the audio data for playback.\n      if (self._webAudio) {\n        loadBuffer(self);\n      }\n\n      return self;\n    },\n\n    /**\n     * Play a sound or resume previous playback.\n     * @param  {String/Number} sprite   Sprite name for sprite playback or sound id to continue previous.\n     * @param  {Boolean} internal Internal Use: true prevents event firing.\n     * @return {Number}          Sound ID.\n     */\n    play: function(sprite, internal) {\n      var self = this;\n      var id = null;\n\n      // Determine if a sprite, sound id or nothing was passed\n      if (typeof sprite === 'number') {\n        id = sprite;\n        sprite = null;\n      } else if (typeof sprite === 'string' && self._state === 'loaded' && !self._sprite[sprite]) {\n        // If the passed sprite doesn't exist, do nothing.\n        return null;\n      } else if (typeof sprite === 'undefined') {\n        // Use the default sound sprite (plays the full audio length).\n        sprite = '__default';\n\n        // Check if there is a single paused sound that isn't ended.\n        // If there is, play that sound. If not, continue as usual.\n        if (!self._playLock) {\n          var num = 0;\n          for (var i=0; i<self._sounds.length; i++) {\n            if (self._sounds[i]._paused && !self._sounds[i]._ended) {\n              num++;\n              id = self._sounds[i]._id;\n            }\n          }\n\n          if (num === 1) {\n            sprite = null;\n          } else {\n            id = null;\n          }\n        }\n      }\n\n      // Get the selected node, or get one from the pool.\n      var sound = id ? self._soundById(id) : self._inactiveSound();\n\n      // If the sound doesn't exist, do nothing.\n      if (!sound) {\n        return null;\n      }\n\n      // Select the sprite definition.\n      if (id && !sprite) {\n        sprite = sound._sprite || '__default';\n      }\n\n      // If the sound hasn't loaded, we must wait to get the audio's duration.\n      // We also need to wait to make sure we don't run into race conditions with\n      // the order of function calls.\n      if (self._state !== 'loaded') {\n        // Set the sprite value on this sound.\n        sound._sprite = sprite;\n\n        // Mark this sound as not ended in case another sound is played before this one loads.\n        sound._ended = false;\n\n        // Add the sound to the queue to be played on load.\n        var soundId = sound._id;\n        self._queue.push({\n          event: 'play',\n          action: function() {\n            self.play(soundId);\n          }\n        });\n\n        return soundId;\n      }\n\n      // Don't play the sound if an id was passed and it is already playing.\n      if (id && !sound._paused) {\n        // Trigger the play event, in order to keep iterating through queue.\n        if (!internal) {\n          self._loadQueue('play');\n        }\n\n        return sound._id;\n      }\n\n      // Make sure the AudioContext isn't suspended, and resume it if it is.\n      if (self._webAudio) {\n        Howler._autoResume();\n      }\n\n      // Determine how long to play for and where to start playing.\n      var seek = Math.max(0, sound._seek > 0 ? sound._seek : self._sprite[sprite][0] / 1000);\n      var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek);\n      var timeout = (duration * 1000) / Math.abs(sound._rate);\n      var start = self._sprite[sprite][0] / 1000;\n      var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;\n      sound._sprite = sprite;\n\n      // Mark the sound as ended instantly so that this async playback\n      // doesn't get grabbed by another call to play while this one waits to start.\n      sound._ended = false;\n\n      // Update the parameters of the sound.\n      var setParams = function() {\n        sound._paused = false;\n        sound._seek = seek;\n        sound._start = start;\n        sound._stop = stop;\n        sound._loop = !!(sound._loop || self._sprite[sprite][2]);\n      };\n\n      // End the sound instantly if seek is at the end.\n      if (seek >= stop) {\n        self._ended(sound);\n        return;\n      }\n\n      // Begin the actual playback.\n      var node = sound._node;\n      if (self._webAudio) {\n        // Fire this when the sound is ready to play to begin Web Audio playback.\n        var playWebAudio = function() {\n          self._playLock = false;\n          setParams();\n          self._refreshBuffer(sound);\n\n          // Setup the playback params.\n          var vol = (sound._muted || self._muted) ? 0 : sound._volume;\n          node.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n          sound._playStart = Howler.ctx.currentTime;\n\n          // Play the sound using the supported method.\n          if (typeof node.bufferSource.start === 'undefined') {\n            sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);\n          } else {\n            sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);\n          }\n\n          // Start a new timer if none is present.\n          if (timeout !== Infinity) {\n            self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n          }\n\n          if (!internal) {\n            setTimeout(function() {\n              self._emit('play', sound._id);\n              self._loadQueue();\n            }, 0);\n          }\n        };\n\n        if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {\n          playWebAudio();\n        } else {\n          self._playLock = true;\n\n          // Wait for the audio context to resume before playing.\n          self.once('resume', playWebAudio);\n\n          // Cancel the end timer.\n          self._clearTimer(sound._id);\n        }\n      } else {\n        // Fire this when the sound is ready to play to begin HTML5 Audio playback.\n        var playHtml5 = function() {\n          node.currentTime = seek;\n          node.muted = sound._muted || self._muted || Howler._muted || node.muted;\n          node.volume = sound._volume * Howler.volume();\n          node.playbackRate = sound._rate;\n\n          // Some browsers will throw an error if this is called without user interaction.\n          try {\n            var play = node.play();\n\n            // Support older browsers that don't support promises, and thus don't have this issue.\n            if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {\n              // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().\n              self._playLock = true;\n\n              // Set param values immediately.\n              setParams();\n\n              // Releases the lock and executes queued actions.\n              play\n                .then(function() {\n                  self._playLock = false;\n                  node._unlocked = true;\n                  if (!internal) {\n                    self._emit('play', sound._id);\n                  } else {\n                    self._loadQueue();\n                  }\n                })\n                .catch(function() {\n                  self._playLock = false;\n                  self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n                    'on mobile devices and Chrome where playback was not within a user interaction.');\n\n                  // Reset the ended and paused values.\n                  sound._ended = true;\n                  sound._paused = true;\n                });\n            } else if (!internal) {\n              self._playLock = false;\n              setParams();\n              self._emit('play', sound._id);\n            }\n\n            // Setting rate before playing won't work in IE, so we set it again here.\n            node.playbackRate = sound._rate;\n\n            // If the node is still paused, then we can assume there was a playback issue.\n            if (node.paused) {\n              self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n                'on mobile devices and Chrome where playback was not within a user interaction.');\n              return;\n            }\n\n            // Setup the end timer on sprites or listen for the ended event.\n            if (sprite !== '__default' || sound._loop) {\n              self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n            } else {\n              self._endTimers[sound._id] = function() {\n                // Fire ended on this audio node.\n                self._ended(sound);\n\n                // Clear this listener.\n                node.removeEventListener('ended', self._endTimers[sound._id], false);\n              };\n              node.addEventListener('ended', self._endTimers[sound._id], false);\n            }\n          } catch (err) {\n            self._emit('playerror', sound._id, err);\n          }\n        };\n\n        // If this is streaming audio, make sure the src is set and load again.\n        if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') {\n          node.src = self._src;\n          node.load();\n        }\n\n        // Play immediately if ready, or wait for the 'canplaythrough'e vent.\n        var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS);\n        if (node.readyState >= 3 || loadedNoReadyState) {\n          playHtml5();\n        } else {\n          self._playLock = true;\n          self._state = 'loading';\n\n          var listener = function() {\n            self._state = 'loaded';\n            \n            // Begin playback.\n            playHtml5();\n\n            // Clear this listener.\n            node.removeEventListener(Howler._canPlayEvent, listener, false);\n          };\n          node.addEventListener(Howler._canPlayEvent, listener, false);\n\n          // Cancel the end timer.\n          self._clearTimer(sound._id);\n        }\n      }\n\n      return sound._id;\n    },\n\n    /**\n     * Pause playback and save current position.\n     * @param  {Number} id The sound ID (empty to pause all in group).\n     * @return {Howl}\n     */\n    pause: function(id) {\n      var self = this;\n\n      // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable.\n      if (self._state !== 'loaded' || self._playLock) {\n        self._queue.push({\n          event: 'pause',\n          action: function() {\n            self.pause(id);\n          }\n        });\n\n        return self;\n      }\n\n      // If no id is passed, get all ID's to be paused.\n      var ids = self._getSoundIds(id);\n\n      for (var i=0; i<ids.length; i++) {\n        // Clear the end timer.\n        self._clearTimer(ids[i]);\n\n        // Get the sound.\n        var sound = self._soundById(ids[i]);\n\n        if (sound && !sound._paused) {\n          // Reset the seek position.\n          sound._seek = self.seek(ids[i]);\n          sound._rateSeek = 0;\n          sound._paused = true;\n\n          // Stop currently running fades.\n          self._stopFade(ids[i]);\n\n          if (sound._node) {\n            if (self._webAudio) {\n              // Make sure the sound has been created.\n              if (!sound._node.bufferSource) {\n                continue;\n              }\n\n              if (typeof sound._node.bufferSource.stop === 'undefined') {\n                sound._node.bufferSource.noteOff(0);\n              } else {\n                sound._node.bufferSource.stop(0);\n              }\n\n              // Clean up the buffer source.\n              self._cleanBuffer(sound._node);\n            } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {\n              sound._node.pause();\n            }\n          }\n        }\n\n        // Fire the pause event, unless `true` is passed as the 2nd argument.\n        if (!arguments[1]) {\n          self._emit('pause', sound ? sound._id : null);\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Stop playback and reset to start.\n     * @param  {Number} id The sound ID (empty to stop all in group).\n     * @param  {Boolean} internal Internal Use: true prevents event firing.\n     * @return {Howl}\n     */\n    stop: function(id, internal) {\n      var self = this;\n\n      // If the sound hasn't loaded, add it to the load queue to stop when capable.\n      if (self._state !== 'loaded' || self._playLock) {\n        self._queue.push({\n          event: 'stop',\n          action: function() {\n            self.stop(id);\n          }\n        });\n\n        return self;\n      }\n\n      // If no id is passed, get all ID's to be stopped.\n      var ids = self._getSoundIds(id);\n\n      for (var i=0; i<ids.length; i++) {\n        // Clear the end timer.\n        self._clearTimer(ids[i]);\n\n        // Get the sound.\n        var sound = self._soundById(ids[i]);\n\n        if (sound) {\n          // Reset the seek position.\n          sound._seek = sound._start || 0;\n          sound._rateSeek = 0;\n          sound._paused = true;\n          sound._ended = true;\n\n          // Stop currently running fades.\n          self._stopFade(ids[i]);\n\n          if (sound._node) {\n            if (self._webAudio) {\n              // Make sure the sound's AudioBufferSourceNode has been created.\n              if (sound._node.bufferSource) {\n                if (typeof sound._node.bufferSource.stop === 'undefined') {\n                  sound._node.bufferSource.noteOff(0);\n                } else {\n                  sound._node.bufferSource.stop(0);\n                }\n\n                // Clean up the buffer source.\n                self._cleanBuffer(sound._node);\n              }\n            } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {\n              sound._node.currentTime = sound._start || 0;\n              sound._node.pause();\n\n              // If this is a live stream, stop download once the audio is stopped.\n              if (sound._node.duration === Infinity) {\n                self._clearSound(sound._node);\n              }\n            }\n          }\n\n          if (!internal) {\n            self._emit('stop', sound._id);\n          }\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Mute/unmute a single sound or all sounds in this Howl group.\n     * @param  {Boolean} muted Set to true to mute and false to unmute.\n     * @param  {Number} id    The sound ID to update (omit to mute/unmute all).\n     * @return {Howl}\n     */\n    mute: function(muted, id) {\n      var self = this;\n\n      // If the sound hasn't loaded, add it to the load queue to mute when capable.\n      if (self._state !== 'loaded'|| self._playLock) {\n        self._queue.push({\n          event: 'mute',\n          action: function() {\n            self.mute(muted, id);\n          }\n        });\n\n        return self;\n      }\n\n      // If applying mute/unmute to all sounds, update the group's value.\n      if (typeof id === 'undefined') {\n        if (typeof muted === 'boolean') {\n          self._muted = muted;\n        } else {\n          return self._muted;\n        }\n      }\n\n      // If no id is passed, get all ID's to be muted.\n      var ids = self._getSoundIds(id);\n\n      for (var i=0; i<ids.length; i++) {\n        // Get the sound.\n        var sound = self._soundById(ids[i]);\n\n        if (sound) {\n          sound._muted = muted;\n\n          // Cancel active fade and set the volume to the end value.\n          if (sound._interval) {\n            self._stopFade(sound._id);\n          }\n\n          if (self._webAudio && sound._node) {\n            sound._node.gain.setValueAtTime(muted ? 0 : sound._volume, Howler.ctx.currentTime);\n          } else if (sound._node) {\n            sound._node.muted = Howler._muted ? true : muted;\n          }\n\n          self._emit('mute', sound._id);\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments.\n     *   volume() -> Returns the group's volume value.\n     *   volume(id) -> Returns the sound id's current volume.\n     *   volume(vol) -> Sets the volume of all sounds in this Howl group.\n     *   volume(vol, id) -> Sets the volume of passed sound id.\n     * @return {Howl/Number} Returns self or current volume.\n     */\n    volume: function() {\n      var self = this;\n      var args = arguments;\n      var vol, id;\n\n      // Determine the values based on arguments.\n      if (args.length === 0) {\n        // Return the value of the groups' volume.\n        return self._volume;\n      } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') {\n        // First check if this is an ID, and if not, assume it is a new volume.\n        var ids = self._getSoundIds();\n        var index = ids.indexOf(args[0]);\n        if (index >= 0) {\n          id = parseInt(args[0], 10);\n        } else {\n          vol = parseFloat(args[0]);\n        }\n      } else if (args.length >= 2) {\n        vol = parseFloat(args[0]);\n        id = parseInt(args[1], 10);\n      }\n\n      // Update the volume or return the current volume.\n      var sound;\n      if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n        // If the sound hasn't loaded, add it to the load queue to change volume when capable.\n        if (self._state !== 'loaded'|| self._playLock) {\n          self._queue.push({\n            event: 'volume',\n            action: function() {\n              self.volume.apply(self, args);\n            }\n          });\n\n          return self;\n        }\n\n        // Set the group volume.\n        if (typeof id === 'undefined') {\n          self._volume = vol;\n        }\n\n        // Update one or all volumes.\n        id = self._getSoundIds(id);\n        for (var i=0; i<id.length; i++) {\n          // Get the sound.\n          sound = self._soundById(id[i]);\n\n          if (sound) {\n            sound._volume = vol;\n\n            // Stop currently running fades.\n            if (!args[2]) {\n              self._stopFade(id[i]);\n            }\n\n            if (self._webAudio && sound._node && !sound._muted) {\n              sound._node.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n            } else if (sound._node && !sound._muted) {\n              sound._node.volume = vol * Howler.volume();\n            }\n\n            self._emit('volume', sound._id);\n          }\n        }\n      } else {\n        sound = id ? self._soundById(id) : self._sounds[0];\n        return sound ? sound._volume : 0;\n      }\n\n      return self;\n    },\n\n    /**\n     * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).\n     * @param  {Number} from The value to fade from (0.0 to 1.0).\n     * @param  {Number} to   The volume to fade to (0.0 to 1.0).\n     * @param  {Number} len  Time in milliseconds to fade.\n     * @param  {Number} id   The sound id (omit to fade all sounds).\n     * @return {Howl}\n     */\n    fade: function(from, to, len, id) {\n      var self = this;\n\n      // If the sound hasn't loaded, add it to the load queue to fade when capable.\n      if (self._state !== 'loaded' || self._playLock) {\n        self._queue.push({\n          event: 'fade',\n          action: function() {\n            self.fade(from, to, len, id);\n          }\n        });\n\n        return self;\n      }\n\n      // Make sure the to/from/len values are numbers.\n      from = Math.min(Math.max(0, parseFloat(from)), 1);\n      to = Math.min(Math.max(0, parseFloat(to)), 1);\n      len = parseFloat(len);\n\n      // Set the volume to the start position.\n      self.volume(from, id);\n\n      // Fade the volume of one or all sounds.\n      var ids = self._getSoundIds(id);\n      for (var i=0; i<ids.length; i++) {\n        // Get the sound.\n        var sound = self._soundById(ids[i]);\n\n        // Create a linear fade or fall back to timeouts with HTML5 Audio.\n        if (sound) {\n          // Stop the previous fade if no sprite is being used (otherwise, volume handles this).\n          if (!id) {\n            self._stopFade(ids[i]);\n          }\n\n          // If we are using Web Audio, let the native methods do the actual fade.\n          if (self._webAudio && !sound._muted) {\n            var currentTime = Howler.ctx.currentTime;\n            var end = currentTime + (len / 1000);\n            sound._volume = from;\n            sound._node.gain.setValueAtTime(from, currentTime);\n            sound._node.gain.linearRampToValueAtTime(to, end);\n          }\n\n          self._startFadeInterval(sound, from, to, len, ids[i], typeof id === 'undefined');\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Starts the internal interval to fade a sound.\n     * @param  {Object} sound Reference to sound to fade.\n     * @param  {Number} from The value to fade from (0.0 to 1.0).\n     * @param  {Number} to   The volume to fade to (0.0 to 1.0).\n     * @param  {Number} len  Time in milliseconds to fade.\n     * @param  {Number} id   The sound id to fade.\n     * @param  {Boolean} isGroup   If true, set the volume on the group.\n     */\n    _startFadeInterval: function(sound, from, to, len, id, isGroup) {\n      var self = this;\n      var vol = from;\n      var diff = to - from;\n      var steps = Math.abs(diff / 0.01);\n      var stepLen = Math.max(4, (steps > 0) ? len / steps : len);\n      var lastTick = Date.now();\n\n      // Store the value being faded to.\n      sound._fadeTo = to;\n\n      // Update the volume value on each interval tick.\n      sound._interval = setInterval(function() {\n        // Update the volume based on the time since the last tick.\n        var tick = (Date.now() - lastTick) / len;\n        lastTick = Date.now();\n        vol += diff * tick;\n\n        // Round to within 2 decimal points.\n        vol = Math.round(vol * 100) / 100;\n\n        // Make sure the volume is in the right bounds.\n        if (diff < 0) {\n          vol = Math.max(to, vol);\n        } else {\n          vol = Math.min(to, vol);\n        }\n\n        // Change the volume.\n        if (self._webAudio) {\n          sound._volume = vol;\n        } else {\n          self.volume(vol, sound._id, true);\n        }\n\n        // Set the group's volume.\n        if (isGroup) {\n          self._volume = vol;\n        }\n\n        // When the fade is complete, stop it and fire event.\n        if ((to < from && vol <= to) || (to > from && vol >= to)) {\n          clearInterval(sound._interval);\n          sound._interval = null;\n          sound._fadeTo = null;\n          self.volume(to, sound._id);\n          self._emit('fade', sound._id);\n        }\n      }, stepLen);\n    },\n\n    /**\n     * Internal method that stops the currently playing fade when\n     * a new fade starts, volume is changed or the sound is stopped.\n     * @param  {Number} id The sound id.\n     * @return {Howl}\n     */\n    _stopFade: function(id) {\n      var self = this;\n      var sound = self._soundById(id);\n\n      if (sound && sound._interval) {\n        if (self._webAudio) {\n          sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime);\n        }\n\n        clearInterval(sound._interval);\n        sound._interval = null;\n        self.volume(sound._fadeTo, id);\n        sound._fadeTo = null;\n        self._emit('fade', id);\n      }\n\n      return self;\n    },\n\n    /**\n     * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.\n     *   loop() -> Returns the group's loop value.\n     *   loop(id) -> Returns the sound id's loop value.\n     *   loop(loop) -> Sets the loop value for all sounds in this Howl group.\n     *   loop(loop, id) -> Sets the loop value of passed sound id.\n     * @return {Howl/Boolean} Returns self or current loop value.\n     */\n    loop: function() {\n      var self = this;\n      var args = arguments;\n      var loop, id, sound;\n\n      // Determine the values for loop and id.\n      if (args.length === 0) {\n        // Return the grou's loop value.\n        return self._loop;\n      } else if (args.length === 1) {\n        if (typeof args[0] === 'boolean') {\n          loop = args[0];\n          self._loop = loop;\n        } else {\n          // Return this sound's loop value.\n          sound = self._soundById(parseInt(args[0], 10));\n          return sound ? sound._loop : false;\n        }\n      } else if (args.length === 2) {\n        loop = args[0];\n        id = parseInt(args[1], 10);\n      }\n\n      // If no id is passed, get all ID's to be looped.\n      var ids = self._getSoundIds(id);\n      for (var i=0; i<ids.length; i++) {\n        sound = self._soundById(ids[i]);\n\n        if (sound) {\n          sound._loop = loop;\n          if (self._webAudio && sound._node && sound._node.bufferSource) {\n            sound._node.bufferSource.loop = loop;\n            if (loop) {\n              sound._node.bufferSource.loopStart = sound._start || 0;\n              sound._node.bufferSource.loopEnd = sound._stop;\n\n              // If playing, restart playback to ensure looping updates.\n              if (self.playing(ids[i])) {\n                self.pause(ids[i], true);\n                self.play(ids[i], true);\n              }\n            }\n          }\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments.\n     *   rate() -> Returns the first sound node's current playback rate.\n     *   rate(id) -> Returns the sound id's current playback rate.\n     *   rate(rate) -> Sets the playback rate of all sounds in this Howl group.\n     *   rate(rate, id) -> Sets the playback rate of passed sound id.\n     * @return {Howl/Number} Returns self or the current playback rate.\n     */\n    rate: function() {\n      var self = this;\n      var args = arguments;\n      var rate, id;\n\n      // Determine the values based on arguments.\n      if (args.length === 0) {\n        // We will simply return the current rate of the first node.\n        id = self._sounds[0]._id;\n      } else if (args.length === 1) {\n        // First check if this is an ID, and if not, assume it is a new rate value.\n        var ids = self._getSoundIds();\n        var index = ids.indexOf(args[0]);\n        if (index >= 0) {\n          id = parseInt(args[0], 10);\n        } else {\n          rate = parseFloat(args[0]);\n        }\n      } else if (args.length === 2) {\n        rate = parseFloat(args[0]);\n        id = parseInt(args[1], 10);\n      }\n\n      // Update the playback rate or return the current value.\n      var sound;\n      if (typeof rate === 'number') {\n        // If the sound hasn't loaded, add it to the load queue to change playback rate when capable.\n        if (self._state !== 'loaded' || self._playLock) {\n          self._queue.push({\n            event: 'rate',\n            action: function() {\n              self.rate.apply(self, args);\n            }\n          });\n\n          return self;\n        }\n\n        // Set the group rate.\n        if (typeof id === 'undefined') {\n          self._rate = rate;\n        }\n\n        // Update one or all volumes.\n        id = self._getSoundIds(id);\n        for (var i=0; i<id.length; i++) {\n          // Get the sound.\n          sound = self._soundById(id[i]);\n\n          if (sound) {\n            // Keep track of our position when the rate changed and update the playback\n            // start position so we can properly adjust the seek position for time elapsed.\n            if (self.playing(id[i])) {\n              sound._rateSeek = self.seek(id[i]);\n              sound._playStart = self._webAudio ? Howler.ctx.currentTime : sound._playStart;\n            }\n            sound._rate = rate;\n\n            // Change the playback rate.\n            if (self._webAudio && sound._node && sound._node.bufferSource) {\n              sound._node.bufferSource.playbackRate.setValueAtTime(rate, Howler.ctx.currentTime);\n            } else if (sound._node) {\n              sound._node.playbackRate = rate;\n            }\n\n            // Reset the timers.\n            var seek = self.seek(id[i]);\n            var duration = ((self._sprite[sound._sprite][0] + self._sprite[sound._sprite][1]) / 1000) - seek;\n            var timeout = (duration * 1000) / Math.abs(sound._rate);\n\n            // Start a new end timer if sound is already playing.\n            if (self._endTimers[id[i]] || !sound._paused) {\n              self._clearTimer(id[i]);\n              self._endTimers[id[i]] = setTimeout(self._ended.bind(self, sound), timeout);\n            }\n\n            self._emit('rate', sound._id);\n          }\n        }\n      } else {\n        sound = self._soundById(id);\n        return sound ? sound._rate : self._rate;\n      }\n\n      return self;\n    },\n\n    /**\n     * Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments.\n     *   seek() -> Returns the first sound node's current seek position.\n     *   seek(id) -> Returns the sound id's current seek position.\n     *   seek(seek) -> Sets the seek position of the first sound node.\n     *   seek(seek, id) -> Sets the seek position of passed sound id.\n     * @return {Howl/Number} Returns self or the current seek position.\n     */\n    seek: function() {\n      var self = this;\n      var args = arguments;\n      var seek, id;\n\n      // Determine the values based on arguments.\n      if (args.length === 0) {\n        // We will simply return the current position of the first node.\n        if (self._sounds.length) {\n          id = self._sounds[0]._id;\n        }\n      } else if (args.length === 1) {\n        // First check if this is an ID, and if not, assume it is a new seek position.\n        var ids = self._getSoundIds();\n        var index = ids.indexOf(args[0]);\n        if (index >= 0) {\n          id = parseInt(args[0], 10);\n        } else if (self._sounds.length) {\n          id = self._sounds[0]._id;\n          seek = parseFloat(args[0]);\n        }\n      } else if (args.length === 2) {\n        seek = parseFloat(args[0]);\n        id = parseInt(args[1], 10);\n      }\n\n      // If there is no ID, bail out.\n      if (typeof id === 'undefined') {\n        return 0;\n      }\n\n      // If the sound hasn't loaded, add it to the load queue to seek when capable.\n      if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)) {\n        self._queue.push({\n          event: 'seek',\n          action: function() {\n            self.seek.apply(self, args);\n          }\n        });\n\n        return self;\n      }\n\n      // Get the sound.\n      var sound = self._soundById(id);\n\n      if (sound) {\n        if (typeof seek === 'number' && seek >= 0) {\n          // Pause the sound and update position for restarting playback.\n          var playing = self.playing(id);\n          if (playing) {\n            self.pause(id, true);\n          }\n\n          // Move the position of the track and cancel timer.\n          sound._seek = seek;\n          sound._ended = false;\n          self._clearTimer(id);\n\n          // Update the seek position for HTML5 Audio.\n          if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {\n            sound._node.currentTime = seek;\n          }\n\n          // Seek and emit when ready.\n          var seekAndEmit = function() {\n            // Restart the playback if the sound was playing.\n            if (playing) {\n              self.play(id, true);\n            }\n\n            self._emit('seek', id);\n          };\n\n          // Wait for the play lock to be unset before emitting (HTML5 Audio).\n          if (playing && !self._webAudio) {\n            var emitSeek = function() {\n              if (!self._playLock) {\n                seekAndEmit();\n              } else {\n                setTimeout(emitSeek, 0);\n              }\n            };\n            setTimeout(emitSeek, 0);\n          } else {\n            seekAndEmit();\n          }\n        } else {\n          if (self._webAudio) {\n            var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;\n            var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;\n            return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));\n          } else {\n            return sound._node.currentTime;\n          }\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.\n     * @param  {Number}  id The sound id to check. If none is passed, the whole sound group is checked.\n     * @return {Boolean} True if playing and false if not.\n     */\n    playing: function(id) {\n      var self = this;\n\n      // Check the passed sound ID (if any).\n      if (typeof id === 'number') {\n        var sound = self._soundById(id);\n        return sound ? !sound._paused : false;\n      }\n\n      // Otherwise, loop through all sounds and check if any are playing.\n      for (var i=0; i<self._sounds.length; i++) {\n        if (!self._sounds[i]._paused) {\n          return true;\n        }\n      }\n\n      return false;\n    },\n\n    /**\n     * Get the duration of this sound. Passing a sound id will return the sprite duration.\n     * @param  {Number} id The sound id to check. If none is passed, return full source duration.\n     * @return {Number} Audio duration in seconds.\n     */\n    duration: function(id) {\n      var self = this;\n      var duration = self._duration;\n\n      // If we pass an ID, get the sound and return the sprite length.\n      var sound = self._soundById(id);\n      if (sound) {\n        duration = self._sprite[sound._sprite][1] / 1000;\n      }\n\n      return duration;\n    },\n\n    /**\n     * Returns the current loaded state of this Howl.\n     * @return {String} 'unloaded', 'loading', 'loaded'\n     */\n    state: function() {\n      return this._state;\n    },\n\n    /**\n     * Unload and destroy the current Howl object.\n     * This will immediately stop all sound instances attached to this group.\n     */\n    unload: function() {\n      var self = this;\n\n      // Stop playing any active sounds.\n      var sounds = self._sounds;\n      for (var i=0; i<sounds.length; i++) {\n        // Stop the sound if it is currently playing.\n        if (!sounds[i]._paused) {\n          self.stop(sounds[i]._id);\n        }\n\n        // Remove the source or disconnect.\n        if (!self._webAudio) {\n          // Set the source to 0-second silence to stop any downloading (except in IE).\n          self._clearSound(sounds[i]._node);\n\n          // Remove any event listeners.\n          sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);\n          sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);\n          sounds[i]._node.removeEventListener('ended', sounds[i]._endFn, false);\n\n          // Release the Audio object back to the pool.\n          Howler._releaseHtml5Audio(sounds[i]._node);\n        }\n\n        // Empty out all of the nodes.\n        delete sounds[i]._node;\n\n        // Make sure all timers are cleared out.\n        self._clearTimer(sounds[i]._id);\n      }\n\n      // Remove the references in the global Howler object.\n      var index = Howler._howls.indexOf(self);\n      if (index >= 0) {\n        Howler._howls.splice(index, 1);\n      }\n\n      // Delete this sound from the cache (if no other Howl is using it).\n      var remCache = true;\n      for (i=0; i<Howler._howls.length; i++) {\n        if (Howler._howls[i]._src === self._src || self._src.indexOf(Howler._howls[i]._src) >= 0) {\n          remCache = false;\n          break;\n        }\n      }\n\n      if (cache && remCache) {\n        delete cache[self._src];\n      }\n\n      // Clear global errors.\n      Howler.noAudio = false;\n\n      // Clear out `self`.\n      self._state = 'unloaded';\n      self._sounds = [];\n      self = null;\n\n      return null;\n    },\n\n    /**\n     * Listen to a custom event.\n     * @param  {String}   event Event name.\n     * @param  {Function} fn    Listener to call.\n     * @param  {Number}   id    (optional) Only listen to events for this sound.\n     * @param  {Number}   once  (INTERNAL) Marks event to fire only once.\n     * @return {Howl}\n     */\n    on: function(event, fn, id, once) {\n      var self = this;\n      var events = self['_on' + event];\n\n      if (typeof fn === 'function') {\n        events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn});\n      }\n\n      return self;\n    },\n\n    /**\n     * Remove a custom event. Call without parameters to remove all events.\n     * @param  {String}   event Event name.\n     * @param  {Function} fn    Listener to remove. Leave empty to remove all.\n     * @param  {Number}   id    (optional) Only remove events for this sound.\n     * @return {Howl}\n     */\n    off: function(event, fn, id) {\n      var self = this;\n      var events = self['_on' + event];\n      var i = 0;\n\n      // Allow passing just an event and ID.\n      if (typeof fn === 'number') {\n        id = fn;\n        fn = null;\n      }\n\n      if (fn || id) {\n        // Loop through event store and remove the passed function.\n        for (i=0; i<events.length; i++) {\n          var isId = (id === events[i].id);\n          if (fn === events[i].fn && isId || !fn && isId) {\n            events.splice(i, 1);\n            break;\n          }\n        }\n      } else if (event) {\n        // Clear out all events of this type.\n        self['_on' + event] = [];\n      } else {\n        // Clear out all events of every type.\n        var keys = Object.keys(self);\n        for (i=0; i<keys.length; i++) {\n          if ((keys[i].indexOf('_on') === 0) && Array.isArray(self[keys[i]])) {\n            self[keys[i]] = [];\n          }\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Listen to a custom event and remove it once fired.\n     * @param  {String}   event Event name.\n     * @param  {Function} fn    Listener to call.\n     * @param  {Number}   id    (optional) Only listen to events for this sound.\n     * @return {Howl}\n     */\n    once: function(event, fn, id) {\n      var self = this;\n\n      // Setup the event listener.\n      self.on(event, fn, id, 1);\n\n      return self;\n    },\n\n    /**\n     * Emit all events of a specific type and pass the sound id.\n     * @param  {String} event Event name.\n     * @param  {Number} id    Sound ID.\n     * @param  {Number} msg   Message to go with event.\n     * @return {Howl}\n     */\n    _emit: function(event, id, msg) {\n      var self = this;\n      var events = self['_on' + event];\n\n      // Loop through event store and fire all functions.\n      for (var i=events.length-1; i>=0; i--) {\n        // Only fire the listener if the correct ID is used.\n        if (!events[i].id || events[i].id === id || event === 'load') {\n          setTimeout(function(fn) {\n            fn.call(this, id, msg);\n          }.bind(self, events[i].fn), 0);\n\n          // If this event was setup with `once`, remove it.\n          if (events[i].once) {\n            self.off(event, events[i].fn, events[i].id);\n          }\n        }\n      }\n\n      // Pass the event type into load queue so that it can continue stepping.\n      self._loadQueue(event);\n\n      return self;\n    },\n\n    /**\n     * Queue of actions initiated before the sound has loaded.\n     * These will be called in sequence, with the next only firing\n     * after the previous has finished executing (even if async like play).\n     * @return {Howl}\n     */\n    _loadQueue: function(event) {\n      var self = this;\n\n      if (self._queue.length > 0) {\n        var task = self._queue[0];\n\n        // Remove this task if a matching event was passed.\n        if (task.event === event) {\n          self._queue.shift();\n          self._loadQueue();\n        }\n\n        // Run the task if no event type is passed.\n        if (!event) {\n          task.action();\n        }\n      }\n\n      return self;\n    },\n\n    /**\n     * Fired when playback ends at the end of the duration.\n     * @param  {Sound} sound The sound object to work with.\n     * @return {Howl}\n     */\n    _ended: function(sound) {\n      var self = this;\n      var sprite = sound._sprite;\n\n      // If we are using IE and there was network latency we may be clipping\n      // audio before it completes playing. Lets check the node to make sure it\n      // believes it has completed, before ending the playback.\n      if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {\n        setTimeout(self._ended.bind(self, sound), 100);\n        return self;\n      }\n\n      // Should this sound loop?\n      var loop = !!(sound._loop || self._sprite[sprite][2]);\n\n      // Fire the ended event.\n      self._emit('end', sound._id);\n\n      // Restart the playback for HTML5 Audio loop.\n      if (!self._webAudio && loop) {\n        self.stop(sound._id, true).play(sound._id);\n      }\n\n      // Restart this timer if on a Web Audio loop.\n      if (self._webAudio && loop) {\n        self._emit('play', sound._id);\n        sound._seek = sound._start || 0;\n        sound._rateSeek = 0;\n        sound._playStart = Howler.ctx.currentTime;\n\n        var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);\n        self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n      }\n\n      // Mark the node as paused.\n      if (self._webAudio && !loop) {\n        sound._paused = true;\n        sound._ended = true;\n        sound._seek = sound._start || 0;\n        sound._rateSeek = 0;\n        self._clearTimer(sound._id);\n\n        // Clean up the buffer source.\n        self._cleanBuffer(sound._node);\n\n        // Attempt to auto-suspend AudioContext if no sounds are still playing.\n        Howler._autoSuspend();\n      }\n\n      // When using a sprite, end the track.\n      if (!self._webAudio && !loop) {\n        self.stop(sound._id, true);\n      }\n\n      return self;\n    },\n\n    /**\n     * Clear the end timer for a sound playback.\n     * @param  {Number} id The sound ID.\n     * @return {Howl}\n     */\n    _clearTimer: function(id) {\n      var self = this;\n\n      if (self._endTimers[id]) {\n        // Clear the timeout or remove the ended listener.\n        if (typeof self._endTimers[id] !== 'function') {\n          clearTimeout(self._endTimers[id]);\n        } else {\n          var sound = self._soundById(id);\n          if (sound && sound._node) {\n            sound._node.removeEventListener('ended', self._endTimers[id], false);\n          }\n        }\n\n        delete self._endTimers[id];\n      }\n\n      return self;\n    },\n\n    /**\n     * Return the sound identified by this ID, or return null.\n     * @param  {Number} id Sound ID\n     * @return {Object}    Sound object or null.\n     */\n    _soundById: function(id) {\n      var self = this;\n\n      // Loop through all sounds and find the one with this ID.\n      for (var i=0; i<self._sounds.length; i++) {\n        if (id === self._sounds[i]._id) {\n          return self._sounds[i];\n        }\n      }\n\n      return null;\n    },\n\n    /**\n     * Return an inactive sound from the pool or create a new one.\n     * @return {Sound} Sound playback object.\n     */\n    _inactiveSound: function() {\n      var self = this;\n\n      self._drain();\n\n      // Find the first inactive node to recycle.\n      for (var i=0; i<self._sounds.length; i++) {\n        if (self._sounds[i]._ended) {\n          return self._sounds[i].reset();\n        }\n      }\n\n      // If no inactive node was found, create a new one.\n      return new Sound(self);\n    },\n\n    /**\n     * Drain excess inactive sounds from the pool.\n     */\n    _drain: function() {\n      var self = this;\n      var limit = self._pool;\n      var cnt = 0;\n      var i = 0;\n\n      // If there are less sounds than the max pool size, we are done.\n      if (self._sounds.length < limit) {\n        return;\n      }\n\n      // Count the number of inactive sounds.\n      for (i=0; i<self._sounds.length; i++) {\n        if (self._sounds[i]._ended) {\n          cnt++;\n        }\n      }\n\n      // Remove excess inactive sounds, going in reverse order.\n      for (i=self._sounds.length - 1; i>=0; i--) {\n        if (cnt <= limit) {\n          return;\n        }\n\n        if (self._sounds[i]._ended) {\n          // Disconnect the audio source when using Web Audio.\n          if (self._webAudio && self._sounds[i]._node) {\n            self._sounds[i]._node.disconnect(0);\n          }\n\n          // Remove sounds until we have the pool size.\n          self._sounds.splice(i, 1);\n          cnt--;\n        }\n      }\n    },\n\n    /**\n     * Get all ID's from the sounds pool.\n     * @param  {Number} id Only return one ID if one is passed.\n     * @return {Array}    Array of IDs.\n     */\n    _getSoundIds: function(id) {\n      var self = this;\n\n      if (typeof id === 'undefined') {\n        var ids = [];\n        for (var i=0; i<self._sounds.length; i++) {\n          ids.push(self._sounds[i]._id);\n        }\n\n        return ids;\n      } else {\n        return [id];\n      }\n    },\n\n    /**\n     * Load the sound back into the buffer source.\n     * @param  {Sound} sound The sound object to work with.\n     * @return {Howl}\n     */\n    _refreshBuffer: function(sound) {\n      var self = this;\n\n      // Setup the buffer source for playback.\n      sound._node.bufferSource = Howler.ctx.createBufferSource();\n      sound._node.bufferSource.buffer = cache[self._src];\n\n      // Connect to the correct node.\n      if (sound._panner) {\n        sound._node.bufferSource.connect(sound._panner);\n      } else {\n        sound._node.bufferSource.connect(sound._node);\n      }\n\n      // Setup looping and playback rate.\n      sound._node.bufferSource.loop = sound._loop;\n      if (sound._loop) {\n        sound._node.bufferSource.loopStart = sound._start || 0;\n        sound._node.bufferSource.loopEnd = sound._stop || 0;\n      }\n      sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler.ctx.currentTime);\n\n      return self;\n    },\n\n    /**\n     * Prevent memory leaks by cleaning up the buffer source after playback.\n     * @param  {Object} node Sound's audio node containing the buffer source.\n     * @return {Howl}\n     */\n    _cleanBuffer: function(node) {\n      var self = this;\n      var isIOS = Howler._navigator && Howler._navigator.vendor.indexOf('Apple') >= 0;\n\n      if (Howler._scratchBuffer && node.bufferSource) {\n        node.bufferSource.onended = null;\n        node.bufferSource.disconnect(0);\n        if (isIOS) {\n          try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {}\n        }\n      }\n      node.bufferSource = null;\n\n      return self;\n    },\n\n    /**\n     * Set the source to a 0-second silence to stop any downloading (except in IE).\n     * @param  {Object} node Audio node to clear.\n     */\n    _clearSound: function(node) {\n      var checkIE = /MSIE |Trident\\//.test(Howler._navigator && Howler._navigator.userAgent);\n      if (!checkIE) {\n        node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';\n      }\n    }\n  };\n\n  /** Single Sound Methods **/\n  /***************************************************************************/\n\n  /**\n   * Setup the sound object, which each node attached to a Howl group is contained in.\n   * @param {Object} howl The Howl parent group.\n   */\n  var Sound = function(howl) {\n    this._parent = howl;\n    this.init();\n  };\n  Sound.prototype = {\n    /**\n     * Initialize a new Sound object.\n     * @return {Sound}\n     */\n    init: function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Setup the default parameters.\n      self._muted = parent._muted;\n      self._loop = parent._loop;\n      self._volume = parent._volume;\n      self._rate = parent._rate;\n      self._seek = 0;\n      self._paused = true;\n      self._ended = true;\n      self._sprite = '__default';\n\n      // Generate a unique ID for this sound.\n      self._id = ++Howler._counter;\n\n      // Add itself to the parent's pool.\n      parent._sounds.push(self);\n\n      // Create the new node.\n      self.create();\n\n      return self;\n    },\n\n    /**\n     * Create and setup a new sound object, whether HTML5 Audio or Web Audio.\n     * @return {Sound}\n     */\n    create: function() {\n      var self = this;\n      var parent = self._parent;\n      var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume;\n\n      if (parent._webAudio) {\n        // Create the gain node for controlling volume (the source will connect to this).\n        self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n        self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime);\n        self._node.paused = true;\n        self._node.connect(Howler.masterGain);\n      } else if (!Howler.noAudio) {\n        // Get an unlocked Audio object from the pool.\n        self._node = Howler._obtainHtml5Audio();\n\n        // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror).\n        self._errorFn = self._errorListener.bind(self);\n        self._node.addEventListener('error', self._errorFn, false);\n\n        // Listen for 'canplaythrough' event to let us know the sound is ready.\n        self._loadFn = self._loadListener.bind(self);\n        self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);\n\n        // Listen for the 'ended' event on the sound to account for edge-case where\n        // a finite sound has a duration of Infinity.\n        self._endFn = self._endListener.bind(self);\n        self._node.addEventListener('ended', self._endFn, false);\n\n        // Setup the new audio node.\n        self._node.src = parent._src;\n        self._node.preload = parent._preload === true ? 'auto' : parent._preload;\n        self._node.volume = volume * Howler.volume();\n\n        // Begin loading the source.\n        self._node.load();\n      }\n\n      return self;\n    },\n\n    /**\n     * Reset the parameters of this sound to the original state (for recycle).\n     * @return {Sound}\n     */\n    reset: function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Reset all of the parameters of this sound.\n      self._muted = parent._muted;\n      self._loop = parent._loop;\n      self._volume = parent._volume;\n      self._rate = parent._rate;\n      self._seek = 0;\n      self._rateSeek = 0;\n      self._paused = true;\n      self._ended = true;\n      self._sprite = '__default';\n\n      // Generate a new ID so that it isn't confused with the previous sound.\n      self._id = ++Howler._counter;\n\n      return self;\n    },\n\n    /**\n     * HTML5 Audio error listener callback.\n     */\n    _errorListener: function() {\n      var self = this;\n\n      // Fire an error event and pass back the code.\n      self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0);\n\n      // Clear the event listener.\n      self._node.removeEventListener('error', self._errorFn, false);\n    },\n\n    /**\n     * HTML5 Audio canplaythrough listener callback.\n     */\n    _loadListener: function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Round up the duration to account for the lower precision in HTML5 Audio.\n      parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n      // Setup a sprite if none is defined.\n      if (Object.keys(parent._sprite).length === 0) {\n        parent._sprite = {__default: [0, parent._duration * 1000]};\n      }\n\n      if (parent._state !== 'loaded') {\n        parent._state = 'loaded';\n        parent._emit('load');\n        parent._loadQueue();\n      }\n\n      // Clear the event listener.\n      self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);\n    },\n\n    /**\n     * HTML5 Audio ended listener callback.\n     */\n    _endListener: function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Only handle the `ended`` event if the duration is Infinity.\n      if (parent._duration === Infinity) {\n        // Update the parent duration to match the real audio duration.\n        // Round up the duration to account for the lower precision in HTML5 Audio.\n        parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n        // Update the sprite that corresponds to the real duration.\n        if (parent._sprite.__default[1] === Infinity) {\n          parent._sprite.__default[1] = parent._duration * 1000;\n        }\n\n        // Run the regular ended method.\n        parent._ended(self);\n      }\n\n      // Clear the event listener since the duration is now correct.\n      self._node.removeEventListener('ended', self._endFn, false);\n    }\n  };\n\n  /** Helper Methods **/\n  /***************************************************************************/\n\n  var cache = {};\n\n  /**\n   * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API).\n   * @param  {Howl} self\n   */\n  var loadBuffer = function(self) {\n    var url = self._src;\n\n    // Check if the buffer has already been cached and use it instead.\n    if (cache[url]) {\n      // Set the duration from the cache.\n      self._duration = cache[url].duration;\n\n      // Load the sound into this Howl.\n      loadSound(self);\n\n      return;\n    }\n\n    if (/^data:[^;]+;base64,/.test(url)) {\n      // Decode the base64 data URI without XHR, since some browsers don't support it.\n      var data = atob(url.split(',')[1]);\n      var dataView = new Uint8Array(data.length);\n      for (var i=0; i<data.length; ++i) {\n        dataView[i] = data.charCodeAt(i);\n      }\n\n      decodeAudioData(dataView.buffer, self);\n    } else {\n      // Load the buffer from the URL.\n      var xhr = new XMLHttpRequest();\n      xhr.open(self._xhr.method, url, true);\n      xhr.withCredentials = self._xhr.withCredentials;\n      xhr.responseType = 'arraybuffer';\n\n      // Apply any custom headers to the request.\n      if (self._xhr.headers) {\n        Object.keys(self._xhr.headers).forEach(function(key) {\n          xhr.setRequestHeader(key, self._xhr.headers[key]);\n        });\n      }\n\n      xhr.onload = function() {\n        // Make sure we get a successful response back.\n        var code = (xhr.status + '')[0];\n        if (code !== '0' && code !== '2' && code !== '3') {\n          self._emit('loaderror', null, 'Failed loading audio file with status: ' + xhr.status + '.');\n          return;\n        }\n\n        decodeAudioData(xhr.response, self);\n      };\n      xhr.onerror = function() {\n        // If there is an error, switch to HTML5 Audio.\n        if (self._webAudio) {\n          self._html5 = true;\n          self._webAudio = false;\n          self._sounds = [];\n          delete cache[url];\n          self.load();\n        }\n      };\n      safeXhrSend(xhr);\n    }\n  };\n\n  /**\n   * Send the XHR request wrapped in a try/catch.\n   * @param  {Object} xhr XHR to send.\n   */\n  var safeXhrSend = function(xhr) {\n    try {\n      xhr.send();\n    } catch (e) {\n      xhr.onerror();\n    }\n  };\n\n  /**\n   * Decode audio data from an array buffer.\n   * @param  {ArrayBuffer} arraybuffer The audio data.\n   * @param  {Howl}        self\n   */\n  var decodeAudioData = function(arraybuffer, self) {\n    // Fire a load error if something broke.\n    var error = function() {\n      self._emit('loaderror', null, 'Decoding audio data failed.');\n    };\n\n    // Load the sound on success.\n    var success = function(buffer) {\n      if (buffer && self._sounds.length > 0) {\n        cache[self._src] = buffer;\n        loadSound(self, buffer);\n      } else {\n        error();\n      }\n    };\n\n    // Decode the buffer into an audio source.\n    if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {\n      Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);\n    } else {\n      Howler.ctx.decodeAudioData(arraybuffer, success, error);\n    }\n  }\n\n  /**\n   * Sound is now loaded, so finish setting everything up and fire the loaded event.\n   * @param  {Howl} self\n   * @param  {Object} buffer The decoded buffer sound source.\n   */\n  var loadSound = function(self, buffer) {\n    // Set the duration.\n    if (buffer && !self._duration) {\n      self._duration = buffer.duration;\n    }\n\n    // Setup a sprite if none is defined.\n    if (Object.keys(self._sprite).length === 0) {\n      self._sprite = {__default: [0, self._duration * 1000]};\n    }\n\n    // Fire the loaded event.\n    if (self._state !== 'loaded') {\n      self._state = 'loaded';\n      self._emit('load');\n      self._loadQueue();\n    }\n  };\n\n  /**\n   * Setup the audio context when available, or switch to HTML5 Audio mode.\n   */\n  var setupAudioContext = function() {\n    // If we have already detected that Web Audio isn't supported, don't run this step again.\n    if (!Howler.usingWebAudio) {\n      return;\n    }\n\n    // Check if we are using Web Audio and setup the AudioContext if we are.\n    try {\n      if (typeof AudioContext !== 'undefined') {\n        Howler.ctx = new AudioContext();\n      } else if (typeof webkitAudioContext !== 'undefined') {\n        Howler.ctx = new webkitAudioContext();\n      } else {\n        Howler.usingWebAudio = false;\n      }\n    } catch(e) {\n      Howler.usingWebAudio = false;\n    }\n\n    // If the audio context creation still failed, set using web audio to false.\n    if (!Howler.ctx) {\n      Howler.usingWebAudio = false;\n    }\n\n    // Check if a webview is being used on iOS8 or earlier (rather than the browser).\n    // If it is, disable Web Audio as it causes crashing.\n    var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform));\n    var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\\d+)_(\\d+)_?(\\d+)?/);\n    var version = appVersion ? parseInt(appVersion[1], 10) : null;\n    if (iOS && version && version < 9) {\n      var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());\n      if (Howler._navigator && !safari) {\n        Howler.usingWebAudio = false;\n      }\n    }\n\n    // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage).\n    if (Howler.usingWebAudio) {\n      Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n      Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime);\n      Howler.masterGain.connect(Howler.ctx.destination);\n    }\n\n    // Re-run the setup on Howler.\n    Howler._setup();\n  };\n\n  // Add support for AMD (Asynchronous Module Definition) libraries such as require.js.\n  if (typeof define === 'function' && define.amd) {\n    define([], function() {\n      return {\n        Howler: Howler,\n        Howl: Howl\n      };\n    });\n  }\n\n  // Add support for CommonJS libraries such as browserify.\n  if (typeof exports !== 'undefined') {\n    exports.Howler = Howler;\n    exports.Howl = Howl;\n  }\n\n  // Add to global in Node.js (for testing, etc).\n  if (typeof global !== 'undefined') {\n    global.HowlerGlobal = HowlerGlobal;\n    global.Howler = Howler;\n    global.Howl = Howl;\n    global.Sound = Sound;\n  } else if (typeof window !== 'undefined') {  // Define globally in case AMD is not available or unused.\n    window.HowlerGlobal = HowlerGlobal;\n    window.Howler = Howler;\n    window.Howl = Howl;\n    window.Sound = Sound;\n  }\n})();\n\n\n/*!\n *  Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.\n *  \n *  howler.js v2.2.3\n *  howlerjs.com\n *\n *  (c) 2013-2020, James Simpson of GoldFire Studios\n *  goldfirestudios.com\n *\n *  MIT License\n */\n\n(function() {\n\n  'use strict';\n\n  // Setup default properties.\n  HowlerGlobal.prototype._pos = [0, 0, 0];\n  HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];\n\n  /** Global Methods **/\n  /***************************************************************************/\n\n  /**\n   * Helper method to update the stereo panning position of all current Howls.\n   * Future Howls will not use this value unless explicitly set.\n   * @param  {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.\n   * @return {Howler/Number}     Self or current stereo panning value.\n   */\n  HowlerGlobal.prototype.stereo = function(pan) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self.ctx || !self.ctx.listener) {\n      return self;\n    }\n\n    // Loop through all Howls and update their stereo panning.\n    for (var i=self._howls.length-1; i>=0; i--) {\n      self._howls[i].stereo(pan);\n    }\n\n    return self;\n  };\n\n  /**\n   * Get/set the position of the listener in 3D cartesian space. Sounds using\n   * 3D position will be relative to the listener's position.\n   * @param  {Number} x The x-position of the listener.\n   * @param  {Number} y The y-position of the listener.\n   * @param  {Number} z The z-position of the listener.\n   * @return {Howler/Array}   Self or current listener position.\n   */\n  HowlerGlobal.prototype.pos = function(x, y, z) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self.ctx || !self.ctx.listener) {\n      return self;\n    }\n\n    // Set the defaults for optional 'y' & 'z'.\n    y = (typeof y !== 'number') ? self._pos[1] : y;\n    z = (typeof z !== 'number') ? self._pos[2] : z;\n\n    if (typeof x === 'number') {\n      self._pos = [x, y, z];\n\n      if (typeof self.ctx.listener.positionX !== 'undefined') {\n        self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);\n      } else {\n        self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);\n      }\n    } else {\n      return self._pos;\n    }\n\n    return self;\n  };\n\n  /**\n   * Get/set the direction the listener is pointing in the 3D cartesian space.\n   * A front and up vector must be provided. The front is the direction the\n   * face of the listener is pointing, and up is the direction the top of the\n   * listener is pointing. Thus, these values are expected to be at right angles\n   * from each other.\n   * @param  {Number} x   The x-orientation of the listener.\n   * @param  {Number} y   The y-orientation of the listener.\n   * @param  {Number} z   The z-orientation of the listener.\n   * @param  {Number} xUp The x-orientation of the top of the listener.\n   * @param  {Number} yUp The y-orientation of the top of the listener.\n   * @param  {Number} zUp The z-orientation of the top of the listener.\n   * @return {Howler/Array}     Returns self or the current orientation vectors.\n   */\n  HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self.ctx || !self.ctx.listener) {\n      return self;\n    }\n\n    // Set the defaults for optional 'y' & 'z'.\n    var or = self._orientation;\n    y = (typeof y !== 'number') ? or[1] : y;\n    z = (typeof z !== 'number') ? or[2] : z;\n    xUp = (typeof xUp !== 'number') ? or[3] : xUp;\n    yUp = (typeof yUp !== 'number') ? or[4] : yUp;\n    zUp = (typeof zUp !== 'number') ? or[5] : zUp;\n\n    if (typeof x === 'number') {\n      self._orientation = [x, y, z, xUp, yUp, zUp];\n\n      if (typeof self.ctx.listener.forwardX !== 'undefined') {\n        self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);\n        self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);\n      } else {\n        self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);\n      }\n    } else {\n      return or;\n    }\n\n    return self;\n  };\n\n  /** Group Methods **/\n  /***************************************************************************/\n\n  /**\n   * Add new properties to the core init.\n   * @param  {Function} _super Core init method.\n   * @return {Howl}\n   */\n  Howl.prototype.init = (function(_super) {\n    return function(o) {\n      var self = this;\n\n      // Setup user-defined default properties.\n      self._orientation = o.orientation || [1, 0, 0];\n      self._stereo = o.stereo || null;\n      self._pos = o.pos || null;\n      self._pannerAttr = {\n        coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360,\n        coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360,\n        coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0,\n        distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse',\n        maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000,\n        panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF',\n        refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1,\n        rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1\n      };\n\n      // Setup event listeners.\n      self._onstereo = o.onstereo ? [{fn: o.onstereo}] : [];\n      self._onpos = o.onpos ? [{fn: o.onpos}] : [];\n      self._onorientation = o.onorientation ? [{fn: o.onorientation}] : [];\n\n      // Complete initilization with howler.js core's init function.\n      return _super.call(this, o);\n    };\n  })(Howl.prototype.init);\n\n  /**\n   * Get/set the stereo panning of the audio source for this sound or all in the group.\n   * @param  {Number} pan  A value of -1.0 is all the way left and 1.0 is all the way right.\n   * @param  {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n   * @return {Howl/Number}    Returns self or the current stereo panning value.\n   */\n  Howl.prototype.stereo = function(pan, id) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self._webAudio) {\n      return self;\n    }\n\n    // If the sound hasn't loaded, add it to the load queue to change stereo pan when capable.\n    if (self._state !== 'loaded') {\n      self._queue.push({\n        event: 'stereo',\n        action: function() {\n          self.stereo(pan, id);\n        }\n      });\n\n      return self;\n    }\n\n    // Check for PannerStereoNode support and fallback to PannerNode if it doesn't exist.\n    var pannerType = (typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo';\n\n    // Setup the group's stereo panning if no ID is passed.\n    if (typeof id === 'undefined') {\n      // Return the group's stereo panning if no parameters are passed.\n      if (typeof pan === 'number') {\n        self._stereo = pan;\n        self._pos = [pan, 0, 0];\n      } else {\n        return self._stereo;\n      }\n    }\n\n    // Change the streo panning of one or all sounds in group.\n    var ids = self._getSoundIds(id);\n    for (var i=0; i<ids.length; i++) {\n      // Get the sound.\n      var sound = self._soundById(ids[i]);\n\n      if (sound) {\n        if (typeof pan === 'number') {\n          sound._stereo = pan;\n          sound._pos = [pan, 0, 0];\n\n          if (sound._node) {\n            // If we are falling back, make sure the panningModel is equalpower.\n            sound._pannerAttr.panningModel = 'equalpower';\n\n            // Check if there is a panner setup and create a new one if not.\n            if (!sound._panner || !sound._panner.pan) {\n              setupPanner(sound, pannerType);\n            }\n\n            if (pannerType === 'spatial') {\n              if (typeof sound._panner.positionX !== 'undefined') {\n                sound._panner.positionX.setValueAtTime(pan, Howler.ctx.currentTime);\n                sound._panner.positionY.setValueAtTime(0, Howler.ctx.currentTime);\n                sound._panner.positionZ.setValueAtTime(0, Howler.ctx.currentTime);\n              } else {\n                sound._panner.setPosition(pan, 0, 0);\n              }\n            } else {\n              sound._panner.pan.setValueAtTime(pan, Howler.ctx.currentTime);\n            }\n          }\n\n          self._emit('stereo', sound._id);\n        } else {\n          return sound._stereo;\n        }\n      }\n    }\n\n    return self;\n  };\n\n  /**\n   * Get/set the 3D spatial position of the audio source for this sound or group relative to the global listener.\n   * @param  {Number} x  The x-position of the audio source.\n   * @param  {Number} y  The y-position of the audio source.\n   * @param  {Number} z  The z-position of the audio source.\n   * @param  {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n   * @return {Howl/Array}    Returns self or the current 3D spatial position: [x, y, z].\n   */\n  Howl.prototype.pos = function(x, y, z, id) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self._webAudio) {\n      return self;\n    }\n\n    // If the sound hasn't loaded, add it to the load queue to change position when capable.\n    if (self._state !== 'loaded') {\n      self._queue.push({\n        event: 'pos',\n        action: function() {\n          self.pos(x, y, z, id);\n        }\n      });\n\n      return self;\n    }\n\n    // Set the defaults for optional 'y' & 'z'.\n    y = (typeof y !== 'number') ? 0 : y;\n    z = (typeof z !== 'number') ? -0.5 : z;\n\n    // Setup the group's spatial position if no ID is passed.\n    if (typeof id === 'undefined') {\n      // Return the group's spatial position if no parameters are passed.\n      if (typeof x === 'number') {\n        self._pos = [x, y, z];\n      } else {\n        return self._pos;\n      }\n    }\n\n    // Change the spatial position of one or all sounds in group.\n    var ids = self._getSoundIds(id);\n    for (var i=0; i<ids.length; i++) {\n      // Get the sound.\n      var sound = self._soundById(ids[i]);\n\n      if (sound) {\n        if (typeof x === 'number') {\n          sound._pos = [x, y, z];\n\n          if (sound._node) {\n            // Check if there is a panner setup and create a new one if not.\n            if (!sound._panner || sound._panner.pan) {\n              setupPanner(sound, 'spatial');\n            }\n\n            if (typeof sound._panner.positionX !== 'undefined') {\n              sound._panner.positionX.setValueAtTime(x, Howler.ctx.currentTime);\n              sound._panner.positionY.setValueAtTime(y, Howler.ctx.currentTime);\n              sound._panner.positionZ.setValueAtTime(z, Howler.ctx.currentTime);\n            } else {\n              sound._panner.setPosition(x, y, z);\n            }\n          }\n\n          self._emit('pos', sound._id);\n        } else {\n          return sound._pos;\n        }\n      }\n    }\n\n    return self;\n  };\n\n  /**\n   * Get/set the direction the audio source is pointing in the 3D cartesian coordinate\n   * space. Depending on how direction the sound is, based on the `cone` attributes,\n   * a sound pointing away from the listener can be quiet or silent.\n   * @param  {Number} x  The x-orientation of the source.\n   * @param  {Number} y  The y-orientation of the source.\n   * @param  {Number} z  The z-orientation of the source.\n   * @param  {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n   * @return {Howl/Array}    Returns self or the current 3D spatial orientation: [x, y, z].\n   */\n  Howl.prototype.orientation = function(x, y, z, id) {\n    var self = this;\n\n    // Stop right here if not using Web Audio.\n    if (!self._webAudio) {\n      return self;\n    }\n\n    // If the sound hasn't loaded, add it to the load queue to change orientation when capable.\n    if (self._state !== 'loaded') {\n      self._queue.push({\n        event: 'orientation',\n        action: function() {\n          self.orientation(x, y, z, id);\n        }\n      });\n\n      return self;\n    }\n\n    // Set the defaults for optional 'y' & 'z'.\n    y = (typeof y !== 'number') ? self._orientation[1] : y;\n    z = (typeof z !== 'number') ? self._orientation[2] : z;\n\n    // Setup the group's spatial orientation if no ID is passed.\n    if (typeof id === 'undefined') {\n      // Return the group's spatial orientation if no parameters are passed.\n      if (typeof x === 'number') {\n        self._orientation = [x, y, z];\n      } else {\n        return self._orientation;\n      }\n    }\n\n    // Change the spatial orientation of one or all sounds in group.\n    var ids = self._getSoundIds(id);\n    for (var i=0; i<ids.length; i++) {\n      // Get the sound.\n      var sound = self._soundById(ids[i]);\n\n      if (sound) {\n        if (typeof x === 'number') {\n          sound._orientation = [x, y, z];\n\n          if (sound._node) {\n            // Check if there is a panner setup and create a new one if not.\n            if (!sound._panner) {\n              // Make sure we have a position to setup the node with.\n              if (!sound._pos) {\n                sound._pos = self._pos || [0, 0, -0.5];\n              }\n\n              setupPanner(sound, 'spatial');\n            }\n\n            if (typeof sound._panner.orientationX !== 'undefined') {\n              sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);\n              sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);\n              sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);\n            } else {\n              sound._panner.setOrientation(x, y, z);\n            }\n          }\n\n          self._emit('orientation', sound._id);\n        } else {\n          return sound._orientation;\n        }\n      }\n    }\n\n    return self;\n  };\n\n  /**\n   * Get/set the panner node's attributes for a sound or group of sounds.\n   * This method can optionall take 0, 1 or 2 arguments.\n   *   pannerAttr() -> Returns the group's values.\n   *   pannerAttr(id) -> Returns the sound id's values.\n   *   pannerAttr(o) -> Set's the values of all sounds in this Howl group.\n   *   pannerAttr(o, id) -> Set's the values of passed sound id.\n   *\n   *   Attributes:\n   *     coneInnerAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n   *                      inside of which there will be no volume reduction.\n   *     coneOuterAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n   *                      outside of which the volume will be reduced to a constant value of `coneOuterGain`.\n   *     coneOuterGain - (0 by default) A parameter for directional audio sources, this is the gain outside of the\n   *                     `coneOuterAngle`. It is a linear value in the range `[0, 1]`.\n   *     distanceModel - ('inverse' by default) Determines algorithm used to reduce volume as audio moves away from\n   *                     listener. Can be `linear`, `inverse` or `exponential.\n   *     maxDistance - (10000 by default) The maximum distance between source and listener, after which the volume\n   *                   will not be reduced any further.\n   *     refDistance - (1 by default) A reference distance for reducing volume as source moves further from the listener.\n   *                   This is simply a variable of the distance model and has a different effect depending on which model\n   *                   is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.\n   *     rolloffFactor - (1 by default) How quickly the volume reduces as source moves from listener. This is simply a\n   *                     variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, ∞]`\n   *                     with `inverse` and `exponential`.\n   *     panningModel - ('HRTF' by default) Determines which spatialization algorithm is used to position audio.\n   *                     Can be `HRTF` or `equalpower`.\n   *\n   * @return {Howl/Object} Returns self or current panner attributes.\n   */\n  Howl.prototype.pannerAttr = function() {\n    var self = this;\n    var args = arguments;\n    var o, id, sound;\n\n    // Stop right here if not using Web Audio.\n    if (!self._webAudio) {\n      return self;\n    }\n\n    // Determine the values based on arguments.\n    if (args.length === 0) {\n      // Return the group's panner attribute values.\n      return self._pannerAttr;\n    } else if (args.length === 1) {\n      if (typeof args[0] === 'object') {\n        o = args[0];\n\n        // Set the grou's panner attribute values.\n        if (typeof id === 'undefined') {\n          if (!o.pannerAttr) {\n            o.pannerAttr = {\n              coneInnerAngle: o.coneInnerAngle,\n              coneOuterAngle: o.coneOuterAngle,\n              coneOuterGain: o.coneOuterGain,\n              distanceModel: o.distanceModel,\n              maxDistance: o.maxDistance,\n              refDistance: o.refDistance,\n              rolloffFactor: o.rolloffFactor,\n              panningModel: o.panningModel\n            };\n          }\n\n          self._pannerAttr = {\n            coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== 'undefined' ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,\n            coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== 'undefined' ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,\n            coneOuterGain: typeof o.pannerAttr.coneOuterGain !== 'undefined' ? o.pannerAttr.coneOuterGain : self._coneOuterGain,\n            distanceModel: typeof o.pannerAttr.distanceModel !== 'undefined' ? o.pannerAttr.distanceModel : self._distanceModel,\n            maxDistance: typeof o.pannerAttr.maxDistance !== 'undefined' ? o.pannerAttr.maxDistance : self._maxDistance,\n            refDistance: typeof o.pannerAttr.refDistance !== 'undefined' ? o.pannerAttr.refDistance : self._refDistance,\n            rolloffFactor: typeof o.pannerAttr.rolloffFactor !== 'undefined' ? o.pannerAttr.rolloffFactor : self._rolloffFactor,\n            panningModel: typeof o.pannerAttr.panningModel !== 'undefined' ? o.pannerAttr.panningModel : self._panningModel\n          };\n        }\n      } else {\n        // Return this sound's panner attribute values.\n        sound = self._soundById(parseInt(args[0], 10));\n        return sound ? sound._pannerAttr : self._pannerAttr;\n      }\n    } else if (args.length === 2) {\n      o = args[0];\n      id = parseInt(args[1], 10);\n    }\n\n    // Update the values of the specified sounds.\n    var ids = self._getSoundIds(id);\n    for (var i=0; i<ids.length; i++) {\n      sound = self._soundById(ids[i]);\n\n      if (sound) {\n        // Merge the new values into the sound.\n        var pa = sound._pannerAttr;\n        pa = {\n          coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : pa.coneInnerAngle,\n          coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : pa.coneOuterAngle,\n          coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : pa.coneOuterGain,\n          distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : pa.distanceModel,\n          maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : pa.maxDistance,\n          refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : pa.refDistance,\n          rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : pa.rolloffFactor,\n          panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : pa.panningModel\n        };\n\n        // Update the panner values or create a new panner if none exists.\n        var panner = sound._panner;\n        if (panner) {\n          panner.coneInnerAngle = pa.coneInnerAngle;\n          panner.coneOuterAngle = pa.coneOuterAngle;\n          panner.coneOuterGain = pa.coneOuterGain;\n          panner.distanceModel = pa.distanceModel;\n          panner.maxDistance = pa.maxDistance;\n          panner.refDistance = pa.refDistance;\n          panner.rolloffFactor = pa.rolloffFactor;\n          panner.panningModel = pa.panningModel;\n        } else {\n          // Make sure we have a position to setup the node with.\n          if (!sound._pos) {\n            sound._pos = self._pos || [0, 0, -0.5];\n          }\n\n          // Create a new panner node.\n          setupPanner(sound, 'spatial');\n        }\n      }\n    }\n\n    return self;\n  };\n\n  /** Single Sound Methods **/\n  /***************************************************************************/\n\n  /**\n   * Add new properties to the core Sound init.\n   * @param  {Function} _super Core Sound init method.\n   * @return {Sound}\n   */\n  Sound.prototype.init = (function(_super) {\n    return function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Setup user-defined default properties.\n      self._orientation = parent._orientation;\n      self._stereo = parent._stereo;\n      self._pos = parent._pos;\n      self._pannerAttr = parent._pannerAttr;\n\n      // Complete initilization with howler.js core Sound's init function.\n      _super.call(this);\n\n      // If a stereo or position was specified, set it up.\n      if (self._stereo) {\n        parent.stereo(self._stereo);\n      } else if (self._pos) {\n        parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);\n      }\n    };\n  })(Sound.prototype.init);\n\n  /**\n   * Override the Sound.reset method to clean up properties from the spatial plugin.\n   * @param  {Function} _super Sound reset method.\n   * @return {Sound}\n   */\n  Sound.prototype.reset = (function(_super) {\n    return function() {\n      var self = this;\n      var parent = self._parent;\n\n      // Reset all spatial plugin properties on this sound.\n      self._orientation = parent._orientation;\n      self._stereo = parent._stereo;\n      self._pos = parent._pos;\n      self._pannerAttr = parent._pannerAttr;\n\n      // If a stereo or position was specified, set it up.\n      if (self._stereo) {\n        parent.stereo(self._stereo);\n      } else if (self._pos) {\n        parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);\n      } else if (self._panner) {\n        // Disconnect the panner.\n        self._panner.disconnect(0);\n        self._panner = undefined;\n        parent._refreshBuffer(self);\n      }\n\n      // Complete resetting of the sound.\n      return _super.call(this);\n    };\n  })(Sound.prototype.reset);\n\n  /** Helper Methods **/\n  /***************************************************************************/\n\n  /**\n   * Create a new panner node and save it on the sound.\n   * @param  {Sound} sound Specific sound to setup panning on.\n   * @param {String} type Type of panner to create: 'stereo' or 'spatial'.\n   */\n  var setupPanner = function(sound, type) {\n    type = type || 'spatial';\n\n    // Create the new panner node.\n    if (type === 'spatial') {\n      sound._panner = Howler.ctx.createPanner();\n      sound._panner.coneInnerAngle = sound._pannerAttr.coneInnerAngle;\n      sound._panner.coneOuterAngle = sound._pannerAttr.coneOuterAngle;\n      sound._panner.coneOuterGain = sound._pannerAttr.coneOuterGain;\n      sound._panner.distanceModel = sound._pannerAttr.distanceModel;\n      sound._panner.maxDistance = sound._pannerAttr.maxDistance;\n      sound._panner.refDistance = sound._pannerAttr.refDistance;\n      sound._panner.rolloffFactor = sound._pannerAttr.rolloffFactor;\n      sound._panner.panningModel = sound._pannerAttr.panningModel;\n\n      if (typeof sound._panner.positionX !== 'undefined') {\n        sound._panner.positionX.setValueAtTime(sound._pos[0], Howler.ctx.currentTime);\n        sound._panner.positionY.setValueAtTime(sound._pos[1], Howler.ctx.currentTime);\n        sound._panner.positionZ.setValueAtTime(sound._pos[2], Howler.ctx.currentTime);\n      } else {\n        sound._panner.setPosition(sound._pos[0], sound._pos[1], sound._pos[2]);\n      }\n\n      if (typeof sound._panner.orientationX !== 'undefined') {\n        sound._panner.orientationX.setValueAtTime(sound._orientation[0], Howler.ctx.currentTime);\n        sound._panner.orientationY.setValueAtTime(sound._orientation[1], Howler.ctx.currentTime);\n        sound._panner.orientationZ.setValueAtTime(sound._orientation[2], Howler.ctx.currentTime);\n      } else {\n        sound._panner.setOrientation(sound._orientation[0], sound._orientation[1], sound._orientation[2]);\n      }\n    } else {\n      sound._panner = Howler.ctx.createStereoPanner();\n      sound._panner.pan.setValueAtTime(sound._stereo, Howler.ctx.currentTime);\n    }\n\n    sound._panner.connect(sound._node);\n\n    // Update the connections.\n    if (!sound._paused) {\n      sound._parent.pause(sound._id, true).play(sound._id, true);\n    }\n  };\n})();\n"],"names":["HowlerGlobal","this","init","prototype","self","Howler","_counter","_html5AudioPool","html5PoolSize","_codecs","_howls","_muted","_volume","_canPlayEvent","_navigator","window","navigator","masterGain","noAudio","usingWebAudio","autoSuspend","ctx","autoUnlock","_setup","volume","vol","parseFloat","setupAudioContext","gain","setValueAtTime","currentTime","i","length","_webAudio","ids","_getSoundIds","j","sound","_soundById","_node","mute","muted","stop","unload","close","codecs","ext","replace","state","_autoSuspend","Audio","oncanplaythrough","e","_setupCodecs","audioTest","err","canPlayType","mpegTest","ua","userAgent","checkOpera","match","isOldOpera","parseInt","split","checkSafari","indexOf","safariVersion","isOldSafari","mp3","mpeg","opus","ogg","oga","wav","aac","caf","m4a","m4b","mp4","weba","webm","dolby","flac","_unlockAudio","_audioUnlocked","_mobileUnloaded","sampleRate","_scratchBuffer","createBuffer","unlock","audioNode","_unlocked","_releaseHtml5Audio","load","_autoResume","source","createBufferSource","buffer","connect","destination","start","noteOn","resume","onended","disconnect","document","removeEventListener","_emit","addEventListener","_obtainHtml5Audio","pop","testPlay","play","Promise","then","catch","console","warn","audio","push","suspend","_sounds","_paused","_suspendTimer","clearTimeout","setTimeout","handleSuspension","_resumeAfterSuspend","Howl","o","src","error","_autoplay","autoplay","_format","format","_html5","html5","_loop","loop","_pool","pool","_preload","preload","_rate","rate","_sprite","sprite","_src","undefined","_xhr","method","xhr","headers","withCredentials","_duration","_state","_endTimers","_queue","_playLock","_onend","onend","fn","_onfade","onfade","_onload","onload","_onloaderror","onloaderror","_onplayerror","onplayerror","_onpause","onpause","_onplay","onplay","_onstop","onstop","_onmute","onmute","_onvolume","onvolume","_onrate","onrate","_onseek","onseek","_onunlock","onunlock","_onresume","event","action","url","str","exec","toLowerCase","location","protocol","slice","Sound","loadBuffer","internal","id","num","_ended","_id","_inactiveSound","soundId","_loadQueue","seek","Math","max","_seek","duration","timeout","abs","setParams","_start","_stop","node","playWebAudio","_refreshBuffer","_playStart","bufferSource","noteGrainOn","Infinity","bind","once","_clearTimer","playHtml5","playbackRate","paused","loadedNoReadyState","ejecta","readyState","isCocoonJS","listener","pause","_rateSeek","_stopFade","noteOff","_cleanBuffer","isNaN","arguments","_clearSound","_interval","args","index","apply","fade","from","to","len","min","end","linearRampToValueAtTime","_startFadeInterval","isGroup","diff","steps","stepLen","lastTick","Date","now","_fadeTo","setInterval","tick","round","clearInterval","cancelScheduledValues","loopStart","loopEnd","playing","realTime","rateSeek","seekAndEmit","emitSeek","sounds","_errorFn","_loadFn","_endFn","splice","remCache","cache","on","events","off","isId","keys","Object","Array","isArray","msg","call","task","shift","ended","_drain","reset","limit","cnt","_panner","isIOS","vendor","test","howl","_parent","parent","create","createGain","createGainNode","_errorListener","_loadListener","_endListener","code","ceil","__default","loadSound","data","atob","dataView","Uint8Array","charCodeAt","decodeAudioData","XMLHttpRequest","open","responseType","forEach","key","setRequestHeader","status","response","onerror","safeXhrSend","send","arraybuffer","success","AudioContext","webkitAudioContext","iOS","platform","appVersion","version","safari","exports","g","_super","_pos","_orientation","stereo","pan","pos","x","y","z","positionX","setTargetAtTime","positionY","positionZ","setPosition","orientation","xUp","yUp","zUp","or","forwardX","forwardY","forwardZ","upX","upY","upZ","setOrientation","_stereo","_pannerAttr","coneInnerAngle","coneOuterAngle","coneOuterGain","distanceModel","maxDistance","panningModel","refDistance","rolloffFactor","_onstereo","onstereo","_onpos","onpos","_onorientation","onorientation","pannerType","createStereoPanner","setupPanner","orientationX","orientationY","orientationZ","pannerAttr","_coneInnerAngle","_coneOuterAngle","_coneOuterGain","_distanceModel","_maxDistance","_refDistance","_rolloffFactor","_panningModel","pa","panner","type","createPanner"],"sourceRoot":""}