lib/sound-manager.js
function SoundManager(manifest) {
  /**
   * A flag signifying if sounds have been muted through {@link SoundManager#mute}.
   * @member {boolean}
   * @private
   */
  this.muted = false;
  /**
   * A key-value object that stores named looping sounds.
   * @member {object}
   * @private
   */
  this.looping = {};

  /**
   * The Web Audio API AudioContext
   * @member {external:AudioContext}
   * @private
   */
  this.context = new window.AudioContext();

  this.gainNode = this.context.createGain();
  this.gainNode.connect(this.context.destination);
  this.volume = this.gainNode.gain.value;
  this.installSafariWorkaround();
  this.assets = new AssetLoader(manifest, loadSound.bind(undefined, this.context));
}
function SoundManager(manifest) {
  /**
   * A flag signifying if sounds have been muted through {@link SoundManager#mute}.
   * @member {boolean}
   * @private
   */
  this.muted = false;
  /**
   * A key-value object that stores named looping sounds.
   * @member {object}
   * @private
   */
  this.looping = {};

  /**
   * The Web Audio API AudioContext
   * @member {external:AudioContext}
   * @private
   */
  this.context = new window.AudioContext();

  this.gainNode = this.context.createGain();
  this.gainNode.connect(this.context.destination);
  this.volume = this.gainNode.gain.value;
  this.installSafariWorkaround();
  this.assets = new AssetLoader(manifest, loadSound.bind(undefined, this.context));
}
Plays audio, tracks looping sounds, and manages volume.
This implementation uses the Web Audio API.
@constructor
@param {Object} manifest A hash where the key is the name of a sound, and the value is the URL of a sound file.