docs: function(sound) {
        var self = this;
        var sprite = sound._sprite;
  
        // If we are using IE and there was network latency we may be clipping
        // audio before it completes playing. Lets check the node to make sure it
        // believes it has completed, before ending the playback.
        if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
          setTimeout(self._ended.bind(self, sound), 100);
          return self;
        }
  
        // Should this sound loop?
        var loop = !!(sound._loop || self._sprite[sprite][2]);
  
        // Fire the ended event.
        self._emit('end', sound._id);
  
        // Restart the playback for HTML5 Audio loop.
        if (!self._webAudio && loop) {
          self.stop(sound._id, true).play(sound._id);
        }
  
        // Restart this timer if on a Web Audio loop.
        if (self._webAudio && loop) {
          self._emit('play', sound._id);
          sound._seek = sound._start || 0;
          sound._rateSeek = 0;
          sound._playStart = Howler.ctx.currentTime;
  
          var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);
          self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
        }
  
        // Mark the node as paused.
        if (self._webAudio && !loop) {
          sound._paused = true;
          sound._ended = true;
          sound._seek = sound._start || 0;
          sound._rateSeek = 0;
          self._clearTimer(sound._id);
  
          // Clean up the buffer source.
          self._cleanBuffer(sound._node);
  
          // Attempt to auto-suspend AudioContext if no sounds are still playing.
          Howler._autoSuspend();
        }
  
        // When using a sprite, end the track.
        if (!self._webAudio && !loop) {
          self.stop(sound._id, true);
        }
  
        return self;
      }