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
};
}());