<!-- NEW4 — TEST 4 · THE QUILT · part 260 -->
ode used for volume control.
		 *
		 * @type {GainNode}
		 * @readonly
		 */
		this.gain = this.context.createGain();
		this.gain.connect( this.context.destination );

		/**
		 * An optional filter.
		 *
		 * Defined via {@link AudioListener#setFilter}.
		 *
		 * @type {?AudioNode}
		 * @default null
		 * @readonly
		 */
		this.filter = null;

		/**
		 * Time delta values required for `linearRampToValueAtTime()` usage.
		 *
		 * @type {number}
		 * @default 0
		 * @readonly
		 */
		this.timeDelta = 0;

		// private

		this._timer = new Timer();

	}

	/**
	 * Returns the listener's input node.
	 *
	 * This method is used by other audio nodes to connect to this listener.
	 *
	 * @return {GainNode} The input node.
	 */
	getInput() {

		return this.gain;

	}

	/**
	 * Removes the current filter from this listener.
	 *
	 * @return {AudioListener} A reference to this listener.
	 */
	removeFilter() {

		if ( this.filter !== null ) {

			this.gain.disconnect( this.filter );
			this.filter.disconnect( this.context.destination );
			this.gain.connect( this.context.destination );
			this.filter = null;

		}

		return this;

	}

	/**
	 * Returns the current set filter.
	 *
	 * @return {?AudioNode} The filter.
	 */
	getFilter() {

		return this.filter;

	}

	/**
	 * Sets the given filter to this listener.
	 *
	 * @param {AudioNode} value - The filter to set.
	 * @return {AudioListener} A reference to this listener.
	 */
	setFilter( value ) {

		if ( this.filter !== null ) {

			this.gain.disconnect( this.filter );
			this.filter.disconnect( this.context.destination );

		} else {

			this.gain.disconnect( this.context.destination );

		}

		this.filter = value;
		this.gain.connect( this.filter );
		this.filter.connect( this.context.destination );

		return this;

	}

	/**
	 * Returns the applications master volume.
	 *
	 * @return {number} The master volume.
	 */
	getMasterVolume() {

		return this.gain.gain.value;

	}

	/**
	 * Sets the applications master volume. This volume setting affects
	 * all audio nodes in the scene.
	 *
	 * @param {number} value - The master volume to set.
	 * @return {AudioListener} A reference to this listener.
	 */
	setMasterVolume( value ) {

		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );

		return this;

	}

	updateMatrixWorld( force ) {

		super.updateMatrixWorld( force );

		this._timer.update();

		const listener = this.context.listener;

		this.timeDelta = this._timer.getDelta();

		this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );

		// the initial forward and up directions must be orthogonal
		_forward.set( 0, 0, -1 ).applyQuaternion( _quaternion$1 );
		_up.set( 0, 1, 0 ).applyQuaternion( _quaternion$1 );

		if ( listener.positionX ) {

			// code path for Chrome (see #14393)

			const endTime = this.context.currentTime + this.timeDelta;

			listener.positionX.linearRampToValueAtTime( _position$1.x, endTime );
			listener.positionY.linearRampToValueAtTime( _position$1.y, endTime );
			listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );
			listener.forwardX.linearRampToValueAtTime( _forward.x, endTime );
			listener.forwardY.linearRampToValueAtTime( _forward.y, endTime );
			listener.forwardZ.linearRampToValueAtTime( _forward.z, endTime );
			listener.upX.linearRampToValueAtTime( _up.x, endTime );
			listener.upY.linearRampToValueAtTime( _up.y, endTime );
			listener.upZ.linearRampToValueAtTime( _up.z, endTime );

		} else {

			listener.setPosition( _position$1.x, _position$1.y, _position$1.z );
			listener.setOrientation( _forward.x, _forward.y, _forward.z, _up.x, _up.y, _up.z );

		}

	}

}

/**
 * Represents a non-positional ( global ) audio object.
 *
 * This and related audio modules make use of the [Web Audio API](https://www.w3.org/TR/webaudio-1.1/).
 *
 * ```js
 * // create an AudioListener and add it to the camera
 * const listener = new THREE.AudioListener();
 * camera.add( listener );
 *
 * // create a global audio source
 * const sound = new THREE.Audio( listener );
 *
 * // load a sound and set it as the Audio object's buffer
 * const audioLoader = new THREE.AudioLoader();
 * audioLoader.load( 'sounds/ambient.ogg', function( buffer ) {
 * 	sound.setBuffer( buffer );
 * 	sound.setLoop( true );
 * 	sound.setVolume( 0.5 );
 * 	sound.play();
 * });
 * ```
 *
 * @augments Object3D
 */
class Audio extends Object3D {

	/**
	 * Constructs a new audio.
	 *
	 * @param {AudioListener} listener - The global audio listener.
	 */
	constructor( listener ) {

		super();

		this.type = 'Audio';

		/**
		 * The global audio listener.
		 *
		 * @type {AudioListener}
		 * @readonly
		 */
		this.listener = listener;

		/**
		 * The audio context.
		 *
		 * @type {AudioContext}
		 * @readonly
		 */
		this.context = listener.context;

		/**
		 * The gain node used for volume control.
		 *
		 * @type {GainNode}
		 * @readonly
		 */
		this.gain = this.context.createGain();
		this.gain