/** * @license * Copyright 2017 Google Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file Distance-based attenuation filter. * @author Andrew Allen */ 'use strict'; // Internal dependencies. import Utils from './utils.js'; /** * @class Attenuation * @description Distance-based attenuation filter. * @param {AudioContext} context * Associated {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. * @param {Object} options * @param {Number} options.minDistance * Min. distance (in meters). Defaults to * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. * @param {Number} options.maxDistance * Max. distance (in meters). Defaults to * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. * @param {string} options.rolloff * Rolloff model to use, chosen from options in * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. */ class Attenuation { constructor(context, options) { // Public variables. /** * Min. distance (in meters). * @member {Number} minDistance * @memberof Attenuation * @instance */ /** * Max. distance (in meters). * @member {Number} maxDistance * @memberof Attenuation * @instance */ /** * Mono (1-channel) input {@link * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. * @member {AudioNode} input * @memberof Attenuation * @instance */ /** * Mono (1-channel) output {@link * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. * @member {AudioNode} output * @memberof Attenuation * @instance */ // Use defaults for undefined arguments. if (options == undefined) { options = {}; } if (options.minDistance == undefined) { options.minDistance = Utils.DEFAULT_MIN_DISTANCE; } if (options.maxDistance == undefined) { options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; } if (options.rolloff == undefined) { options.rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; } // Assign values. this.minDistance = options.minDistance; this.maxDistance = options.maxDistance; this.setRolloff(options.rolloff); // Create node. this._gainNode = context.createGain(); // Initialize distance to max distance. this.setDistance(options.maxDistance); // Input/Output proxy. this.input = this._gainNode; this.output = this._gainNode; } /** * Set distance from the listener. * @param {Number} distance Distance (in meters). */ setDistance(distance) { let gain = 1; if (this._rolloff == 'logarithmic') { if (distance > this.maxDistance) { gain = 0; } else if (distance > this.minDistance) { let range = this.maxDistance - this.minDistance; if (range > Utils.EPSILON_FLOAT) { // Compute the distance attenuation value by the logarithmic curve // "1 / (d + 1)" with an offset of |minDistance|. let relativeDistance = distance - this.minDistance; let attenuation = 1 / (relativeDistance + 1); let attenuationMax = 1 / (range + 1); gain = (attenuation - attenuationMax) / (1 - attenuationMax); } } } else if (this._rolloff == 'linear') { if (distance > this.maxDistance) { gain = 0; } else if (distance > this.minDistance) { let range = this.maxDistance - this.minDistance; if (range > Utils.EPSILON_FLOAT) { gain = (this.maxDistance - distance) / range; } } } this._gainNode.gain.value = gain; } /** * Set rolloff. * @param {string} rolloff * Rolloff model to use, chosen from options in * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. */ setRolloff(rolloff) { let isValidModel = ~Utils.ATTENUATION_ROLLOFFS.indexOf(rolloff); if (rolloff == undefined || !isValidModel) { if (!isValidModel) { Utils.log('Invalid rolloff model (\"' + rolloff + '\"). Using default: \"' + Utils.DEFAULT_ATTENUATION_ROLLOFF + '\".'); } rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; } else { rolloff = rolloff.toString().toLowerCase(); } this._rolloff = rolloff; } } export default Attenuation;