214 lines
8.4 KiB
JavaScript
214 lines
8.4 KiB
JavaScript
|
/**
|
||
|
* @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;
|