| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- import { Vector3 } from '../math/Vector3.js';
- import { Quaternion } from '../math/Quaternion.js';
- import { Audio } from './Audio.js';
- const _position = /*@__PURE__*/ new Vector3();
- const _quaternion = /*@__PURE__*/ new Quaternion();
- const _scale = /*@__PURE__*/ new Vector3();
- const _orientation = /*@__PURE__*/ new Vector3();
- /**
- * Represents a positional audio object.
- *
- * ```js
- * // create an AudioListener and add it to the camera
- * const listener = new THREE.AudioListener();
- * camera.add( listener );
- *
- * // create the PositionalAudio object (passing in the listener)
- * const sound = new THREE.PositionalAudio( listener );
- *
- * // load a sound and set it as the PositionalAudio object's buffer
- * const audioLoader = new THREE.AudioLoader();
- * audioLoader.load( 'sounds/song.ogg', function( buffer ) {
- * sound.setBuffer( buffer );
- * sound.setRefDistance( 20 );
- * sound.play();
- * });
- *
- * // create an object for the sound to play from
- * const sphere = new THREE.SphereGeometry( 20, 32, 16 );
- * const material = new THREE.MeshPhongMaterial( { color: 0xff2200 } );
- * const mesh = new THREE.Mesh( sphere, material );
- * scene.add( mesh );
- *
- * // finally add the sound to the mesh
- * mesh.add( sound );
- *
- * @augments Audio
- */
- class PositionalAudio extends Audio {
- /**
- * Constructs a positional audio.
- *
- * @param {AudioListener} listener - The global audio listener.
- */
- constructor( listener ) {
- super( listener );
- /**
- * The panner node represents the location, direction, and behavior of an audio
- * source in 3D space.
- *
- * @type {PannerNode}
- * @readonly
- */
- this.panner = this.context.createPanner();
- this.panner.panningModel = 'HRTF';
- this.panner.connect( this.gain );
- }
- connect() {
- super.connect();
- this.panner.connect( this.gain );
- return this;
- }
- disconnect() {
- super.disconnect();
- this.panner.disconnect( this.gain );
- return this;
- }
- getOutput() {
- return this.panner;
- }
- /**
- * Returns the current reference distance.
- *
- * @return {number} The reference distance.
- */
- getRefDistance() {
- return this.panner.refDistance;
- }
- /**
- * Defines the reference distance for reducing volume as the audio source moves
- * further from the listener – i.e. the distance at which the volume reduction
- * starts taking effect.
- *
- * @param {number} value - The reference distance to set.
- * @return {PositionalAudio} A reference to this instance.
- */
- setRefDistance( value ) {
- this.panner.refDistance = value;
- return this;
- }
- /**
- * Returns the current rolloff factor.
- *
- * @return {number} The rolloff factor.
- */
- getRolloffFactor() {
- return this.panner.rolloffFactor;
- }
- /**
- * Defines how quickly the volume is reduced as the source moves away from the listener.
- *
- * @param {number} value - The rolloff factor.
- * @return {PositionalAudio} A reference to this instance.
- */
- setRolloffFactor( value ) {
- this.panner.rolloffFactor = value;
- return this;
- }
- /**
- * Returns the current distance model.
- *
- * @return {('linear'|'inverse'|'exponential')} The distance model.
- */
- getDistanceModel() {
- return this.panner.distanceModel;
- }
- /**
- * Defines which algorithm to use to reduce the volume of the audio source
- * as it moves away from the listener.
- *
- * Read [the spec]{@link https://www.w3.org/TR/webaudio-1.1/#enumdef-distancemodeltype}
- * for more details.
- *
- * @param {('linear'|'inverse'|'exponential')} value - The distance model to set.
- * @return {PositionalAudio} A reference to this instance.
- */
- setDistanceModel( value ) {
- this.panner.distanceModel = value;
- return this;
- }
- /**
- * Returns the current max distance.
- *
- * @return {number} The max distance.
- */
- getMaxDistance() {
- return this.panner.maxDistance;
- }
- /**
- * Defines the maximum distance between the audio source and the listener,
- * after which the volume is not reduced any further.
- *
- * This value is used only by the `linear` distance model.
- *
- * @param {number} value - The max distance.
- * @return {PositionalAudio} A reference to this instance.
- */
- setMaxDistance( value ) {
- this.panner.maxDistance = value;
- return this;
- }
- /**
- * Sets the directional cone in which the audio can be listened.
- *
- * @param {number} coneInnerAngle - An angle, in degrees, of a cone inside of which there will be no volume reduction.
- * @param {number} coneOuterAngle - An angle, in degrees, of a cone outside of which the volume will be reduced by a constant value, defined by the `coneOuterGain` parameter.
- * @param {number} coneOuterGain - The amount of volume reduction outside the cone defined by the `coneOuterAngle`. When set to `0`, no sound can be heard.
- * @return {PositionalAudio} A reference to this instance.
- */
- setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
- this.panner.coneInnerAngle = coneInnerAngle;
- this.panner.coneOuterAngle = coneOuterAngle;
- this.panner.coneOuterGain = coneOuterGain;
- return this;
- }
- updateMatrixWorld( force ) {
- super.updateMatrixWorld( force );
- if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
- this.matrixWorld.decompose( _position, _quaternion, _scale );
- _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );
- const panner = this.panner;
- if ( panner.positionX ) {
- // code path for Chrome and Firefox (see #14393)
- const endTime = this.context.currentTime + this.listener.timeDelta;
- panner.positionX.linearRampToValueAtTime( _position.x, endTime );
- panner.positionY.linearRampToValueAtTime( _position.y, endTime );
- panner.positionZ.linearRampToValueAtTime( _position.z, endTime );
- panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );
- panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );
- panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );
- } else {
- panner.setPosition( _position.x, _position.y, _position.z );
- panner.setOrientation( _orientation.x, _orientation.y, _orientation.z );
- }
- }
- }
- export { PositionalAudio };
|