text: Object.assign(pc, function () {
      'use strict';
  
      // default maxDistance, same as Web Audio API
      var MAX_DISTANCE = 10000;
  
      var Channel3d;
  
      if (pc.AudioManager.hasAudioContext()) {
          Channel3d = function (manager, sound, options) {
              pc.Channel.call(this, manager, sound, options);
  
              this.position = new pc.Vec3();
              this.velocity = new pc.Vec3();
  
              var context = manager.context;
              this.panner = context.createPanner();
          };
          Channel3d.prototype = Object.create(pc.Channel.prototype);
          Channel3d.prototype.constructor = Channel3d;
  
          Object.assign(Channel3d.prototype, {
              getPosition: function () {
                  return this.position;
              },
  
              setPosition: function (position) {
                  this.position.copy(position);
                  this.panner.setPosition(position.x, position.y, position.z);
              },
  
              getVelocity: function () {
                  return this.velocity;
              },
  
              setVelocity: function (velocity) {
                  this.velocity.copy(velocity);
                  this.panner.setVelocity(velocity.x, velocity.y, velocity.z);
              },
  
              getMaxDistance: function () {
                  return this.panner.maxDistance;
              },
  
              setMaxDistance: function (max) {
                  this.panner.maxDistance = max;
              },
  
              getMinDistance: function () {
                  return this.panner.refDistance;
              },
  
              setMinDistance: function (min) {
                  this.panner.refDistance = min;
              },
  
              getRollOffFactor: function () {
                  return this.panner.rolloffFactor;
              },
  
              setRollOffFactor: function (factor) {
                  this.panner.rolloffFactor = factor;
              },
  
              getDistanceModel: function () {
                  return this.pannel.distanceModel;
              },
  
              setDistanceModel: function (distanceModel) {
                  this.panner.distanceModel = distanceModel;
              },
  
              /**
               * @private
               * @function
               * @name pc.Channel3d#_createSource
               * @description Create the buffer source and connect it up to the correct audio nodes
               */
              _createSource: function () {
                  var context = this.manager.context;
  
                  this.source = context.createBufferSource();
                  this.source.buffer = this.sound.buffer;
  
                  // Connect up the nodes
                  this.source.connect(this.panner);
                  this.panner.connect(this.gain);
                  this.gain.connect(context.destination);
  
                  if (!this.loop) {
                      // mark source as paused when it ends
                      this.source.onended = this.pause.bind(this);
                  }
              }
          });
      } else if (pc.AudioManager.hasAudio()) {
          // temp vector storage
          var offset = new pc.Vec3();
  
  
          // Fall off function which should be the same as the one in the Web Audio API
          // Taken from https://developer.mozilla.org/en-US/docs/Web/API/PannerNode/distanceModel
          var fallOff = function (posOne, posTwo, refDistance, maxDistance, rolloffFactor, distanceModel) {
              offset = offset.sub2(posOne, posTwo);
              var distance = offset.length();
  
              if (distance < refDistance) {
                  return 1;
              } else if (distance > maxDistance) {
                  return 0;
              }
  
              var result = 0;
              if (distanceModel === pc.DISTANCE_LINEAR) {
                  result = 1 - rolloffFactor * (distance - refDistance) / (maxDistance - refDistance);
              } else if (distanceModel === pc.DISTANCE_INVERSE) {
                  result = refDistance / (refDistance + rolloffFactor * (distance - refDistance));
              } else if (distanceModel === pc.DISTANCE_EXPONENTIAL) {
                  result = Math.pow(distance / refDistance, -rolloffFactor);
              }
              return pc.math.clamp(result, 0, 1);
          };
  
          Channel3d = function (manager, sound) {
              pc.Channel.call(this, manager, sound);
  
              this.position = new pc.Vec3();
              this.velocity = new pc.Vec3();
  
              this.maxDistance = MAX_DISTANCE;
              this.minDistance = 1;
              this.rollOffFactor = 1;
              this.distanceModel = pc.DISTANCE_INVERSE;
          };
          Channel3d.prototype = Object.create(pc.Channel.prototype);
          Channel3d.prototype.constructor = Channel3d;
  
          Object.assign(Channel3d.prototype, {
              getPosition: function () {
                  return this.position;
              },
  
              setPosition: function (position) {
                  this.position.copy(position);
  
                  if (this.source) {
                      var listener = this.manager.listener;
  
                      var lpos = listener.getPosition();
  
                      var factor = fallOff(lpos, this.position, this.minDistance, this.maxDistance, this.rollOffFactor, this.distanceModel);
  
                      var v = this.getVolume();
                      this.source.volume = v * factor;
                  }
              },
  
              getVelocity: function () {
                  return this.velocity;
              },
  
              setVelocity: function (velocity) {
                  this.velocity.copy(velocity);
              },
  
              getMaxDistance: function () {
                  return this.maxDistance;
              },
  
              setMaxDistance: function (max) {
                  this.maxDistance = max;
              },
  
              getMinDistance: function () {
                  return this.minDistance;
              },
  
              setMinDistance: function (min) {
                  this.minDistance = min;
              },
  
              getRollOffFactor: function () {
                  return this.rollOffFactor;
              },
  
              setRollOffFactor: function (factor) {
                  this.rollOffFactor = factor;
              },
  
              getDistanceModel: function () {
                  return this.distanceModel;
              },
  
              setDistanceModel: function (distanceModel) {
                  this.distanceModel = distanceModel;
              }
          });
      } else {
          Channel3d = function () { };
      }
  
      return {
          Channel3d: Channel3d
      };
  }());
  