assassin-bug/framework/resonator/vendor/resonance-es6/resonance-audio.js

214 lines
8.4 KiB
JavaScript
Raw Permalink Normal View History

2022-11-26 01:22:02 +00:00
/**
* @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 ResonanceAudio library name space and common utilities.
* @author Andrew Allen <bitllama@google.com>
*/
'use strict';
// Internal dependencies.
import Listener from './listener.js';
import Source from './source.js';
import Room from './room.js';
import Encoder from './encoder.js';
import Utils from './utils.js';
/**
* Options for constructing a new ResonanceAudio scene.
* @typedef {Object} ResonanceAudio~ResonanceAudioOptions
* @property {Number} ambisonicOrder
* Desired ambisonic Order. Defaults to
* {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
* @property {Float32Array} listenerPosition
* The listener's initial position (in meters), where origin is the center of
* the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
* @property {Float32Array} listenerForward
* The listener's initial forward vector.
* Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
* @property {Float32Array} listenerUp
* The listener's initial up vector.
* Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
* @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
* @property {Utils~RoomMaterials} materials Named acoustic materials per wall.
* Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
* @property {Number} speedOfSound
* (in meters/second). Defaults to
* {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
*/
/**
* @class ResonanceAudio
* @description Main class for managing sources, room and listener models.
* @param {AudioContext} context
* Associated {@link
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
* @param {ResonanceAudio~ResonanceAudioOptions} options
* Options for constructing a new ResonanceAudio scene.
*/
class ResonanceAudio {
constructor(context, options) {
// Public variables.
/**
* Binaurally-rendered stereo (2-channel) output {@link
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
* @member {AudioNode} output
* @memberof ResonanceAudio
* @instance
*/
/**
* Ambisonic (multichannel) input {@link
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}
* (For rendering input soundfields).
* @member {AudioNode} ambisonicInput
* @memberof ResonanceAudio
* @instance
*/
/**
* Ambisonic (multichannel) output {@link
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}
* (For allowing external rendering / post-processing).
* @member {AudioNode} ambisonicOutput
* @memberof ResonanceAudio
* @instance
*/
// Use defaults for undefined arguments.
if (options == undefined) {
options = {};
}
if (options.ambisonicOrder == undefined) {
options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
}
if (options.listenerPosition == undefined) {
options.listenerPosition = Utils.DEFAULT_POSITION.slice();
}
if (options.listenerForward == undefined) {
options.listenerForward = Utils.DEFAULT_FORWARD.slice();
}
if (options.listenerUp == undefined) {
options.listenerUp = Utils.DEFAULT_UP.slice();
}
if (options.dimensions == undefined) {
options.dimensions = {};
Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS);
}
if (options.materials == undefined) {
options.materials = {};
Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS);
}
if (options.speedOfSound == undefined) {
options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
}
// Create member submodules.
this._ambisonicOrder = Encoder.validateAmbisonicOrder(options.ambisonicOrder);
this._sources = [];
this._room = new Room(context, {
listenerPosition: options.listenerPosition,
dimensions: options.dimensions,
materials: options.materials,
speedOfSound: options.speedOfSound,
});
this._listener = new Listener(context, {
ambisonicOrder: options.ambisonicOrder,
position: options.listenerPosition,
forward: options.listenerForward,
up: options.listenerUp,
});
// Create auxillary audio nodes.
this._context = context;
this.output = context.createGain();
this.ambisonicOutput = context.createGain();
this.ambisonicInput = this._listener.input;
// Connect audio graph.
this._room.output.connect(this._listener.input);
this._listener.output.connect(this.output);
this._listener.ambisonicOutput.connect(this.ambisonicOutput);
}
/**
* Create a new source for the scene.
* @param {Source~SourceOptions} options
* Options for constructing a new Source.
* @return {Source}
*/
createSource(options) {
// Create a source and push it to the internal sources array, returning
// the object's reference to the user.
let source = new Source(this, options);
this._sources[this._sources.length] = source;
return source;
}
/**
* Set the scene's desired ambisonic order.
* @param {Number} ambisonicOrder Desired ambisonic order.
*/
setAmbisonicOrder(ambisonicOrder) {
this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder);
}
/**
* Set the room's dimensions and wall materials.
* @param {Object} dimensions Room dimensions (in meters).
* @param {Object} materials Named acoustic materials per wall.
*/
setRoomProperties(dimensions, materials) {
this._room.setProperties(dimensions, materials);
}
/**
* Set the listener's position (in meters), where origin is the center of
* the room.
* @param {Number} x
* @param {Number} y
* @param {Number} z
*/
setListenerPosition(x, y, z) {
// Update listener position.
this._listener.position[0] = x;
this._listener.position[1] = y;
this._listener.position[2] = z;
this._room.setListenerPosition(x, y, z);
// Update sources with new listener position.
this._sources.forEach(element => {
element._update();
});
}
/**
* Set the source's orientation using forward and up vectors.
* @param {Number} forwardX
* @param {Number} forwardY
* @param {Number} forwardZ
* @param {Number} upX
* @param {Number} upY
* @param {Number} upZ
*/
setListenerOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
this._listener.setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ);
}
/**
* Set the listener's position and orientation using a Three.js Matrix4 object.
* @param {Object} matrix
* The Three.js Matrix4 object representing the listener's world transform.
*/
setListenerFromMatrix(matrix) {
this._listener.setFromMatrix(matrix);
// Update the rest of the scene using new listener position.
this.setListenerPosition(this._listener.position[0], this._listener.position[1], this._listener.position[2]);
}
/**
* Set the speed of sound.
* @param {Number} speedOfSound
*/
setSpeedOfSound(speedOfSound) {
this._room.speedOfSound = speedOfSound;
}
}
export default ResonanceAudio;