Update framework
This commit is contained in:
11
framework/resonator/audio-context.d.ts
vendored
Normal file
11
framework/resonator/audio-context.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export default class ResonatorAudioContext {
|
||||
private context;
|
||||
constructor();
|
||||
getContext(): AudioContext;
|
||||
createGain(): any;
|
||||
getOutputDestination(): AudioNode;
|
||||
createBufferSource(): AudioBufferSourceNode;
|
||||
decodeAudioData(data: ArrayBuffer): Promise<AudioBuffer>;
|
||||
createPanner(): any;
|
||||
createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode;
|
||||
}
|
39
framework/resonator/audio-context.js
Normal file
39
framework/resonator/audio-context.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// simple wrapper around the AudioContext
|
||||
// eventually will be used to deal with cross browser issues
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
export default class ResonatorAudioContext {
|
||||
constructor() {
|
||||
this.context = new AudioContext();
|
||||
}
|
||||
getContext() {
|
||||
return this.context;
|
||||
}
|
||||
createGain() {
|
||||
return this.context.createGain();
|
||||
}
|
||||
getOutputDestination() {
|
||||
return this.context.destination;
|
||||
}
|
||||
createBufferSource() {
|
||||
return this.context.createBufferSource();
|
||||
}
|
||||
decodeAudioData(data) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return yield this.context.decodeAudioData(data);
|
||||
});
|
||||
}
|
||||
createPanner() {
|
||||
return this.context.createPanner();
|
||||
}
|
||||
createMediaElementSource(element) {
|
||||
return this.context.createMediaElementSource(element);
|
||||
}
|
||||
}
|
21
framework/resonator/audio-graph.d.ts
vendored
Normal file
21
framework/resonator/audio-graph.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import ResonatorScene from './scenes/webaudio-scene';
|
||||
import ResonatorAudioContext from './audio-context';
|
||||
import BaseEffect from './effects/base-effect';
|
||||
export default class AudioGraph {
|
||||
private master;
|
||||
private effectsBus;
|
||||
private worldBus;
|
||||
private secondaryBus;
|
||||
private effects;
|
||||
private scene;
|
||||
private context;
|
||||
private swapChannels;
|
||||
private channelSplitter;
|
||||
private channelMerger;
|
||||
constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean);
|
||||
init(): void;
|
||||
connectToMaster(input: any): void;
|
||||
connectToUI(input: AudioNode): void;
|
||||
applyEffect(effect: BaseEffect): void;
|
||||
removeEffect(effect: BaseEffect): void;
|
||||
}
|
46
framework/resonator/audio-graph.js
Normal file
46
framework/resonator/audio-graph.js
Normal file
@@ -0,0 +1,46 @@
|
||||
// this is the mixer that takes all the different outputs and mixes them into the 2 busses:
|
||||
// WorldBus: The directional audio
|
||||
// SecondaryBus: All the UI and things that are non directional
|
||||
import EffectChain from './effect-chain';
|
||||
export default class AudioGraph {
|
||||
constructor(scene, context, swapChannels = false) {
|
||||
this.scene = scene;
|
||||
this.context = context;
|
||||
this.swapChannels = swapChannels;
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
this.effectsBus = this.context.createGain();
|
||||
this.worldBus = this.context.createGain();
|
||||
this.secondaryBus = this.context.createGain();
|
||||
this.master = this.context.createGain();
|
||||
this.scene.getOutput().connect(this.worldBus);
|
||||
// this.worldBus.connect(this.master);
|
||||
this.worldBus.connect(this.effectsBus);
|
||||
this.effects = new EffectChain(this.context, this, this.effectsBus, this.master);
|
||||
this.secondaryBus.connect(this.master);
|
||||
if (this.swapChannels) {
|
||||
this.channelSplitter = this.context.getContext().createChannelSplitter(2);
|
||||
this.channelMerger = this.context.getContext().createChannelMerger(2);
|
||||
this.master.connect(this.channelSplitter);
|
||||
this.channelSplitter.connect(this.channelMerger, 0, 1);
|
||||
this.channelSplitter.connect(this.channelMerger, 1, 0);
|
||||
this.channelMerger.connect(this.context.getOutputDestination());
|
||||
}
|
||||
else {
|
||||
this.master.connect(this.context.getOutputDestination());
|
||||
}
|
||||
}
|
||||
connectToMaster(input) {
|
||||
input.connect(this.master);
|
||||
}
|
||||
connectToUI(input) {
|
||||
input.connect(this.secondaryBus);
|
||||
}
|
||||
applyEffect(effect) {
|
||||
this.effects.applyEffect(effect);
|
||||
}
|
||||
removeEffect(effect) {
|
||||
this.effects.removeEffect(effect);
|
||||
}
|
||||
}
|
12
framework/resonator/data-pool-item.d.ts
vendored
Normal file
12
framework/resonator/data-pool-item.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export default class DataPoolItem {
|
||||
private name;
|
||||
private data;
|
||||
private decodedData;
|
||||
constructor(name: string, data?: any, decodedData?: any);
|
||||
getData(): any;
|
||||
setData(data: any): void;
|
||||
getDecodedData(): any;
|
||||
setDecodedData(data: any): void;
|
||||
getName(): string;
|
||||
setName(name: string): void;
|
||||
}
|
26
framework/resonator/data-pool-item.js
Normal file
26
framework/resonator/data-pool-item.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// An item in the data pool
|
||||
export default class DataPoolItem {
|
||||
constructor(name, data = null, decodedData = null) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.decodedData = decodedData;
|
||||
}
|
||||
getData() {
|
||||
return this.data;
|
||||
}
|
||||
setData(data) {
|
||||
this.data = data;
|
||||
}
|
||||
getDecodedData() {
|
||||
return this.decodedData;
|
||||
}
|
||||
setDecodedData(data) {
|
||||
this.decodedData = this.decodedData;
|
||||
}
|
||||
getName() {
|
||||
return this.name;
|
||||
}
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
12
framework/resonator/data-pool.d.ts
vendored
Normal file
12
framework/resonator/data-pool.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import ResonatorAudioContext from './audio-context';
|
||||
import { BaseLoader } from './loaders/base-loader';
|
||||
export default class DataPool extends EventEmitter {
|
||||
private loader;
|
||||
private data;
|
||||
private maxData;
|
||||
private context;
|
||||
constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number);
|
||||
get(path: string): Promise<AudioBuffer>;
|
||||
clear(): void;
|
||||
}
|
48
framework/resonator/data-pool.js
Normal file
48
framework/resonator/data-pool.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import DataPoolItem from './data-pool-item';
|
||||
import { HTTPLoader } from './loaders/http-loader';
|
||||
export default class DataPool extends EventEmitter {
|
||||
constructor(context, loader = new HTTPLoader(), maxData = 512) {
|
||||
super();
|
||||
this.loader = loader;
|
||||
this.data = {};
|
||||
this.maxData = maxData;
|
||||
this.context = context;
|
||||
}
|
||||
get(path) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.data[path]) {
|
||||
return this.data[path].getDecodedData();
|
||||
}
|
||||
else {
|
||||
const buffer = yield this.loader.get(path);
|
||||
const decoded = yield this.context.decodeAudioData(buffer);
|
||||
const item = new DataPoolItem(path, buffer, decoded);
|
||||
const length = Object.keys(this.data).length;
|
||||
if (length < this.maxData) {
|
||||
this.data[path] = item;
|
||||
}
|
||||
else {
|
||||
// TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them.
|
||||
// const paths: string[] = Object.keys(this.data);
|
||||
// delete this.data[paths[0]];
|
||||
this.data[path] = item;
|
||||
}
|
||||
return item.getDecodedData();
|
||||
}
|
||||
});
|
||||
}
|
||||
clear() {
|
||||
this.data = {};
|
||||
}
|
||||
}
|
8
framework/resonator/effect-bus.d.ts
vendored
Normal file
8
framework/resonator/effect-bus.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import ResonatorAudioContext from './audio-context';
|
||||
export default class EffectBus {
|
||||
private context;
|
||||
private inputNode;
|
||||
private channelMerger;
|
||||
constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode);
|
||||
connect(node: AudioNode): void;
|
||||
}
|
12
framework/resonator/effect-bus.js
Normal file
12
framework/resonator/effect-bus.js
Normal file
@@ -0,0 +1,12 @@
|
||||
// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on
|
||||
export default class EffectBus {
|
||||
constructor(context, input, output) {
|
||||
this.context = context;
|
||||
this.inputNode = input;
|
||||
this.channelMerger = this.context.getContext().createChannelMerger(1);
|
||||
this.inputNode.connect(this.channelMerger);
|
||||
}
|
||||
connect(node) {
|
||||
this.channelMerger.connect(node);
|
||||
}
|
||||
}
|
14
framework/resonator/effect-chain.d.ts
vendored
Normal file
14
framework/resonator/effect-chain.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import ResonatorAudioContext from './audio-context';
|
||||
import AudioGraph from './audio-graph';
|
||||
import BaseEffect from './effects/base-effect';
|
||||
export default class EffectChain {
|
||||
private context;
|
||||
private graph;
|
||||
private effects;
|
||||
private inputNode;
|
||||
private outputNode;
|
||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode);
|
||||
applyEffect(effect: BaseEffect): void;
|
||||
removeEffect(effect: BaseEffect): void;
|
||||
private updateConnections;
|
||||
}
|
45
framework/resonator/effect-chain.js
Normal file
45
framework/resonator/effect-chain.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// A chain of effects that connect to the effect bus
|
||||
export default class EffectChain {
|
||||
constructor(context, graph, input, output) {
|
||||
this.effects = [];
|
||||
this.context = context;
|
||||
this.graph = graph;
|
||||
this.inputNode = input;
|
||||
this.outputNode = output;
|
||||
this.updateConnections();
|
||||
}
|
||||
applyEffect(effect) {
|
||||
this.effects.push(effect);
|
||||
this.updateConnections();
|
||||
}
|
||||
removeEffect(effect) {
|
||||
this.effects.forEach((currEffect) => {
|
||||
if (effect === currEffect) {
|
||||
currEffect.disconnect();
|
||||
}
|
||||
});
|
||||
this.effects = this.effects.filter((currEffect) => effect !== currEffect);
|
||||
this.updateConnections();
|
||||
}
|
||||
updateConnections() {
|
||||
if (this.effects.length == 0) {
|
||||
this.inputNode.connect(this.outputNode);
|
||||
return;
|
||||
}
|
||||
let current = null;
|
||||
let previous = null;
|
||||
this.effects.forEach((effect) => {
|
||||
current = effect;
|
||||
if (previous) {
|
||||
current.connectInput(previous.getOutput());
|
||||
}
|
||||
else {
|
||||
current.connectInput(this.inputNode);
|
||||
}
|
||||
previous = current;
|
||||
});
|
||||
if (current) {
|
||||
current.connectOutput(this.outputNode);
|
||||
}
|
||||
}
|
||||
}
|
15
framework/resonator/effects/base-effect.d.ts
vendored
Normal file
15
framework/resonator/effects/base-effect.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import AudioGraph from '../audio-graph';
|
||||
export default class BaseEffect {
|
||||
protected ready: boolean;
|
||||
protected effectNode: any;
|
||||
protected effectParams: any;
|
||||
protected context: ResonatorAudioContext;
|
||||
protected graph: AudioGraph;
|
||||
protected inputNode: AudioNode;
|
||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
|
||||
connectOutput(node: AudioNode): void;
|
||||
connectInput(node: AudioNode): void;
|
||||
getOutput(): AudioNode;
|
||||
disconnect(): void;
|
||||
}
|
23
framework/resonator/effects/base-effect.js
Normal file
23
framework/resonator/effects/base-effect.js
Normal file
@@ -0,0 +1,23 @@
|
||||
export default class BaseEffect {
|
||||
constructor(context, graph, params) {
|
||||
this.graph = graph;
|
||||
this.context = context;
|
||||
this.effectParams = params;
|
||||
}
|
||||
connectOutput(node) {
|
||||
this.effectNode.connect(node);
|
||||
}
|
||||
connectInput(node) {
|
||||
this.inputNode = node;
|
||||
if (this.effectNode) {
|
||||
this.inputNode.connect(this.effectNode);
|
||||
}
|
||||
}
|
||||
getOutput() {
|
||||
return this.effectNode;
|
||||
}
|
||||
disconnect() {
|
||||
this.inputNode.disconnect();
|
||||
this.effectNode.disconnect();
|
||||
}
|
||||
}
|
10
framework/resonator/effects/convolver.d.ts
vendored
Normal file
10
framework/resonator/effects/convolver.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import BaseEffect from './base-effect';
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import AudioGraph from '../audio-graph';
|
||||
export default class Convolver extends BaseEffect {
|
||||
private buffer;
|
||||
private channelSplitter;
|
||||
private channelMerger;
|
||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
|
||||
connectInput(node: AudioNode): void;
|
||||
}
|
20
framework/resonator/effects/convolver.js
Normal file
20
framework/resonator/effects/convolver.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import BaseEffect from './base-effect';
|
||||
export default class Convolver extends BaseEffect {
|
||||
constructor(context, graph, params) {
|
||||
super(context, graph, params);
|
||||
console.log(`Creating convolver`);
|
||||
this.effectNode = this.context.getContext().createConvolver();
|
||||
this.effectNode.buffer = this.effectParams.buffer;
|
||||
}
|
||||
connectInput(node) {
|
||||
this.channelSplitter = this.context.getContext().createChannelSplitter(2);
|
||||
this.channelMerger = this.context.getContext().createChannelMerger(2);
|
||||
this.channelSplitter.connect(this.channelMerger, 0, 0);
|
||||
this.channelSplitter.connect(this.channelMerger, 1, 0);
|
||||
this.channelSplitter.connect(this.channelMerger, 0, 1);
|
||||
this.channelSplitter.connect(this.channelMerger, 1, 1);
|
||||
node.connect(this.channelSplitter);
|
||||
this.channelMerger.connect(this.effectNode);
|
||||
this.inputNode = node;
|
||||
}
|
||||
}
|
22
framework/resonator/index.d.ts
vendored
Normal file
22
framework/resonator/index.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import AudioSource from './sources/audio-source';
|
||||
import { BaseLoader } from './loaders/base-loader';
|
||||
import { BaseSource } from './sources/base-source';
|
||||
import { SourceType } from './sources/source-type';
|
||||
import { StreamingSource } from './sources/streaming-source';
|
||||
export default class Resonator {
|
||||
private loader;
|
||||
private context;
|
||||
private scene;
|
||||
private graph;
|
||||
private dataPool;
|
||||
private environmentImpulse;
|
||||
constructor(loader?: BaseLoader);
|
||||
load(path: string, type?: SourceType): Promise<BaseSource>;
|
||||
loadImmediate(path: string, type?: SourceType): AudioSource;
|
||||
stream(path: string, type?: SourceType): StreamingSource;
|
||||
private createSource;
|
||||
setEnvironmentImpulse(file: string): Promise<void>;
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
setListenerOrientation(forward: any, up: any): void;
|
||||
clearDataPool(): void;
|
||||
}
|
78
framework/resonator/index.js
Normal file
78
framework/resonator/index.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// the main module for Resonator
|
||||
// API, etc.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import ResonatorAudioContext from './audio-context';
|
||||
import ResonatorScene from './scenes/webaudio-scene';
|
||||
import AudioGraph from './audio-graph';
|
||||
import AudioSource from './sources/audio-source';
|
||||
import DataPool from './data-pool';
|
||||
import Convolver from './effects/convolver';
|
||||
import { HTTPLoader } from './loaders/http-loader';
|
||||
import { SourceType } from './sources/source-type';
|
||||
import { StreamingSource } from './sources/streaming-source';
|
||||
export default class Resonator {
|
||||
constructor(loader = new HTTPLoader()) {
|
||||
this.loader = loader;
|
||||
this.environmentImpulse = null;
|
||||
this.context = new ResonatorAudioContext();
|
||||
this.scene = new ResonatorScene(this.context);
|
||||
this.graph = new AudioGraph(this.scene, this.context, false);
|
||||
this.dataPool = new DataPool(this.context, this.loader);
|
||||
}
|
||||
load(path, type = SourceType.WorldSource) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const data = yield this.dataPool.get(path);
|
||||
const source = this.createSource(type, data);
|
||||
return source;
|
||||
});
|
||||
}
|
||||
loadImmediate(path, type = SourceType.WorldSource) {
|
||||
const source = new AudioSource(this.graph, this.scene, this.context, null, type);
|
||||
this.dataPool.get(path).then((data) => {
|
||||
source.setBuffer(data);
|
||||
});
|
||||
return source;
|
||||
}
|
||||
stream(path, type = SourceType.MasterSource) {
|
||||
const element = new Audio(path);
|
||||
element.crossOrigin = 'anonymous';
|
||||
element.volume = 1;
|
||||
const source = new StreamingSource(this.graph, this.scene, this.context, element, type);
|
||||
return source;
|
||||
}
|
||||
createSource(type, data) {
|
||||
return new AudioSource(this.graph, this.scene, this.context, data);
|
||||
}
|
||||
setEnvironmentImpulse(file) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.environmentImpulse) {
|
||||
this.graph.removeEffect(this.environmentImpulse);
|
||||
}
|
||||
if (file === null) {
|
||||
return;
|
||||
}
|
||||
const buffer = yield this.dataPool.get(file);
|
||||
this.environmentImpulse = new Convolver(this.context, this.graph, {
|
||||
buffer
|
||||
});
|
||||
this.graph.applyEffect(this.environmentImpulse);
|
||||
});
|
||||
}
|
||||
setListenerPosition(x, y, z) {
|
||||
this.scene.setListenerPosition(x, y, z);
|
||||
}
|
||||
setListenerOrientation(forward, up) {
|
||||
this.scene.setListenerOrientation(forward, up);
|
||||
}
|
||||
clearDataPool() {
|
||||
this.dataPool.clear();
|
||||
}
|
||||
}
|
10
framework/resonator/loaders/asset-loader.d.ts
vendored
Normal file
10
framework/resonator/loaders/asset-loader.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { AssetManager } from '../../asset-manager';
|
||||
import { BaseLoader } from './base-loader';
|
||||
export declare class AssetLoader implements BaseLoader {
|
||||
private name;
|
||||
private manager;
|
||||
private assetManager;
|
||||
constructor(name: string, manager?: AssetManager);
|
||||
init(): Promise<void>;
|
||||
get(path: string): Promise<ArrayBuffer>;
|
||||
}
|
36
framework/resonator/loaders/asset-loader.js
Normal file
36
framework/resonator/loaders/asset-loader.js
Normal file
@@ -0,0 +1,36 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
// TODO fix path when actually properly linking the packages together
|
||||
import { AssetManager } from '../../asset-manager';
|
||||
export class AssetLoader {
|
||||
constructor(name, manager = null) {
|
||||
this.name = name;
|
||||
this.manager = manager;
|
||||
if (manager) {
|
||||
this.assetManager = manager;
|
||||
}
|
||||
else {
|
||||
this.assetManager = new AssetManager(name, '');
|
||||
}
|
||||
}
|
||||
init() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.assetManager.init();
|
||||
});
|
||||
}
|
||||
get(path) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = yield this.assetManager.downloadFile(path);
|
||||
console.log(result);
|
||||
const buffer = yield result.arrayBuffer();
|
||||
return buffer;
|
||||
});
|
||||
}
|
||||
}
|
3
framework/resonator/loaders/base-loader.d.ts
vendored
Normal file
3
framework/resonator/loaders/base-loader.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface BaseLoader {
|
||||
get(path: string): Promise<ArrayBuffer>;
|
||||
}
|
1
framework/resonator/loaders/base-loader.js
Normal file
1
framework/resonator/loaders/base-loader.js
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
4
framework/resonator/loaders/http-loader.d.ts
vendored
Normal file
4
framework/resonator/loaders/http-loader.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { BaseLoader } from './base-loader';
|
||||
export declare class HTTPLoader implements BaseLoader {
|
||||
get(path: string): Promise<ArrayBuffer>;
|
||||
}
|
18
framework/resonator/loaders/http-loader.js
Normal file
18
framework/resonator/loaders/http-loader.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
export class HTTPLoader {
|
||||
get(path) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = yield fetch(path);
|
||||
const buffer = yield result.arrayBuffer();
|
||||
return buffer;
|
||||
});
|
||||
}
|
||||
}
|
14
framework/resonator/scenes/resonance-scene.d.ts
vendored
Normal file
14
framework/resonator/scenes/resonance-scene.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import EventEmitter from 'eventemitter3';
|
||||
export default class Scene extends EventEmitter {
|
||||
scene: any;
|
||||
context: ResonatorAudioContext;
|
||||
listener: AudioListener;
|
||||
constructor(context: ResonatorAudioContext);
|
||||
init(): void;
|
||||
createSource(): any;
|
||||
getOutput(): any;
|
||||
getInput(): any;
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
setListenerOrientation(forward: any, rawup: any): void;
|
||||
}
|
40
framework/resonator/scenes/resonance-scene.js
Normal file
40
framework/resonator/scenes/resonance-scene.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// The code that deals with 3d audio
|
||||
import ResonanceAudio from '../vendor/resonance-es6/main';
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import vec3 from '../../tsm/vec3';
|
||||
export default class Scene extends EventEmitter {
|
||||
constructor(context) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.scene = new ResonanceAudio(this.context.getContext(), {
|
||||
ambisonicOrder: 3
|
||||
});
|
||||
this.listener = this.context.getContext().listener;
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
// this.scene.output.connect(this.context.getOutputDestination());
|
||||
}
|
||||
createSource() {
|
||||
const source = this.scene.createSource();
|
||||
return Object.assign(Object.assign({}, source), { getInput: () => source.input });
|
||||
}
|
||||
getOutput() {
|
||||
return this.scene.output;
|
||||
}
|
||||
getInput() {
|
||||
return this.scene.input;
|
||||
}
|
||||
setListenerPosition(x, y, z) {
|
||||
this.scene.setListenerPosition(x, y, z);
|
||||
}
|
||||
setListenerOrientation(forward, rawup) {
|
||||
let fwd = new vec3([forward.x, forward.y, forward.z]);
|
||||
let up = fwd.copy();
|
||||
vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
|
||||
vec3.cross(up, fwd, up);
|
||||
fwd.normalize();
|
||||
up.normalize();
|
||||
this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z);
|
||||
}
|
||||
}
|
14
framework/resonator/scenes/webaudio-scene.d.ts
vendored
Normal file
14
framework/resonator/scenes/webaudio-scene.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import EventEmitter from 'eventemitter3';
|
||||
export default class ResonatorScene extends EventEmitter {
|
||||
scene: GainNode;
|
||||
context: ResonatorAudioContext;
|
||||
listener: AudioListener;
|
||||
constructor(context: ResonatorAudioContext);
|
||||
init(): void;
|
||||
createSource(): any;
|
||||
getOutput(): any;
|
||||
getInput(): any;
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
setListenerOrientation(forward: any, rawup: any): void;
|
||||
}
|
42
framework/resonator/scenes/webaudio-scene.js
Normal file
42
framework/resonator/scenes/webaudio-scene.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// The code that deals with 3d audio
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import vec3 from '../../tsm/vec3';
|
||||
export default class ResonatorScene extends EventEmitter {
|
||||
constructor(context) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.scene = this.context.getContext().createGain();
|
||||
this.listener = this.context.getContext().listener;
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
// this.scene.output.connect(this.context.getOutputDestination());
|
||||
}
|
||||
createSource() {
|
||||
const node = this.context.getContext().createPanner();
|
||||
node.panningModel = 'HRTF';
|
||||
node.distanceModel = 'linear';
|
||||
node.maxDistance = 20;
|
||||
node.refDistance = 2;
|
||||
node.connect(this.scene);
|
||||
return node;
|
||||
}
|
||||
getOutput() {
|
||||
return this.scene;
|
||||
}
|
||||
getInput() {
|
||||
return this.scene;
|
||||
}
|
||||
setListenerPosition(x, y, z) {
|
||||
this.listener.setPosition(x, y, z);
|
||||
}
|
||||
setListenerOrientation(forward, rawup) {
|
||||
let fwd = new vec3([forward.x, forward.y, forward.z]);
|
||||
let up = fwd.copy();
|
||||
vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
|
||||
vec3.cross(up, fwd, up);
|
||||
fwd.normalize();
|
||||
up.normalize();
|
||||
this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
||||
}
|
||||
}
|
37
framework/resonator/sources/audio-source.d.ts
vendored
Normal file
37
framework/resonator/sources/audio-source.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import AudioGraph from '../audio-graph';
|
||||
import ResonatorScene from '../scenes/webaudio-scene';
|
||||
import { BaseSource } from './base-source';
|
||||
import { SourceType } from './source-type';
|
||||
export default class AudioSource implements BaseSource {
|
||||
playing: boolean;
|
||||
looping: boolean;
|
||||
private node;
|
||||
private sceneNode;
|
||||
private buffer;
|
||||
private context;
|
||||
private graph;
|
||||
private scene;
|
||||
private playOnLoad;
|
||||
private position;
|
||||
private playbackRate;
|
||||
private volume;
|
||||
private gain;
|
||||
private type;
|
||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType);
|
||||
init(): void;
|
||||
getBuffer(): AudioBuffer;
|
||||
setBuffer(data: AudioBuffer): void;
|
||||
play(when?: number, offset?: number, duration?: number): void;
|
||||
setPosition(x: number, y: number, z: number): void;
|
||||
setPlaybackRate(rate: number): void;
|
||||
getPlaybackRate(): number;
|
||||
setVolume(volume: number): void;
|
||||
getVolume(): number;
|
||||
private createConnections;
|
||||
stop(): void;
|
||||
destroy(): void;
|
||||
loop(value: boolean): void;
|
||||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
}
|
148
framework/resonator/sources/audio-source.js
Normal file
148
framework/resonator/sources/audio-source.js
Normal file
@@ -0,0 +1,148 @@
|
||||
// an audio source
|
||||
// This is the actual sound
|
||||
import { SourceType } from './source-type';
|
||||
export default class AudioSource {
|
||||
constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) {
|
||||
this.position = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
this.buffer = buffer;
|
||||
this.context = context;
|
||||
this.scene = scene;
|
||||
this.graph = graph;
|
||||
this.type = type;
|
||||
this.playbackRate = 1;
|
||||
this.volume = 1;
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
this.gain = this.context.createGain();
|
||||
// bind methods so we can add and removve them from event listeners
|
||||
this.stop = this.stop.bind(this);
|
||||
}
|
||||
getBuffer() {
|
||||
return this.buffer;
|
||||
}
|
||||
setBuffer(data) {
|
||||
this.buffer = data;
|
||||
if (this.playOnLoad) {
|
||||
this.play();
|
||||
this.playOnLoad = false;
|
||||
}
|
||||
}
|
||||
play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) {
|
||||
if (this.playing && this.node) {
|
||||
this.stop();
|
||||
}
|
||||
if (!this.buffer) {
|
||||
this.playOnLoad = true;
|
||||
return;
|
||||
}
|
||||
if (!this.node) {
|
||||
this.node = this.context.createBufferSource();
|
||||
this.node.buffer = this.buffer;
|
||||
this.createConnections();
|
||||
}
|
||||
if (this.node) {
|
||||
this.node.playbackRate.value = this.playbackRate;
|
||||
this.node.start(when, offset, duration);
|
||||
this.node.loop = this.looping;
|
||||
this.playing = true;
|
||||
if (this.sceneNode) {
|
||||
this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z);
|
||||
}
|
||||
this.node.addEventListener('ended', this.stop);
|
||||
}
|
||||
}
|
||||
setPosition(x, y, z) {
|
||||
this.position = {
|
||||
x,
|
||||
y,
|
||||
z
|
||||
};
|
||||
if (this.sceneNode)
|
||||
this.sceneNode.setPosition(x, y, z);
|
||||
}
|
||||
setPlaybackRate(rate) {
|
||||
this.playbackRate = rate;
|
||||
if (this.node)
|
||||
this.node.playbackRate.value = rate;
|
||||
}
|
||||
getPlaybackRate() {
|
||||
return this.playbackRate;
|
||||
}
|
||||
setVolume(volume) {
|
||||
this.volume = volume;
|
||||
if (this.gain)
|
||||
this.gain.gain.value = volume;
|
||||
}
|
||||
getVolume() {
|
||||
return this.volume;
|
||||
}
|
||||
createConnections() {
|
||||
switch (this.type) {
|
||||
case SourceType.WorldSource:
|
||||
if (!this.sceneNode) {
|
||||
this.sceneNode = this.scene.createSource();
|
||||
}
|
||||
this.node.connect(this.gain);
|
||||
this.gain.connect(this.sceneNode);
|
||||
break;
|
||||
case SourceType.UISource:
|
||||
this.node.connect(this.gain);
|
||||
this.graph.connectToUI(this.gain);
|
||||
break;
|
||||
default:
|
||||
this.node.connect(this.gain);
|
||||
this.graph.connectToMaster(this.gain);
|
||||
break;
|
||||
}
|
||||
}
|
||||
stop() {
|
||||
this.playing = false;
|
||||
if (this.node) {
|
||||
this.node.removeEventListener('ended', this.stop);
|
||||
this.node.stop();
|
||||
this.node.disconnect();
|
||||
this.node = null;
|
||||
this.playing = false;
|
||||
if (this.sceneNode) {
|
||||
this.sceneNode.disconnect();
|
||||
this.sceneNode = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
destroy() {
|
||||
this.stop();
|
||||
// set all refs to null to encourage gc
|
||||
this.node = null;
|
||||
this.sceneNode = null;
|
||||
this.buffer = null;
|
||||
this.context = null;
|
||||
this.graph = null;
|
||||
this.scene = null;
|
||||
}
|
||||
loop(value) {
|
||||
this.looping = value;
|
||||
if (this.node) {
|
||||
this.node.loop = value;
|
||||
}
|
||||
}
|
||||
fadeOut(time) {
|
||||
this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime);
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
||||
setTimeout(() => this.stop(), time * 1000);
|
||||
}
|
||||
fadeIn(time) {
|
||||
this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime);
|
||||
if (!this.node) {
|
||||
this.play();
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time);
|
||||
}
|
||||
}
|
12
framework/resonator/sources/base-source.d.ts
vendored
Normal file
12
framework/resonator/sources/base-source.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface BaseSource {
|
||||
play(when: number, offset: number, duration: number): void;
|
||||
stop(): void;
|
||||
setPlaybackRate(value: number): void;
|
||||
getPlaybackRate(): number;
|
||||
setVolume(value: number): void;
|
||||
getVolume(): number;
|
||||
loop(value: boolean): void;
|
||||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
destroy(): void;
|
||||
}
|
1
framework/resonator/sources/base-source.js
Normal file
1
framework/resonator/sources/base-source.js
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
5
framework/resonator/sources/source-type.d.ts
vendored
Normal file
5
framework/resonator/sources/source-type.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export declare enum SourceType {
|
||||
WorldSource = 0,
|
||||
UISource = 1,
|
||||
MasterSource = 2
|
||||
}
|
6
framework/resonator/sources/source-type.js
Normal file
6
framework/resonator/sources/source-type.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export var SourceType;
|
||||
(function (SourceType) {
|
||||
SourceType[SourceType["WorldSource"] = 0] = "WorldSource";
|
||||
SourceType[SourceType["UISource"] = 1] = "UISource";
|
||||
SourceType[SourceType["MasterSource"] = 2] = "MasterSource";
|
||||
})(SourceType || (SourceType = {}));
|
33
framework/resonator/sources/streaming-source.d.ts
vendored
Normal file
33
framework/resonator/sources/streaming-source.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { BaseSource } from './base-source';
|
||||
import AudioGraph from '../audio-graph';
|
||||
import ResonatorScene from '../scenes/webaudio-scene';
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import { SourceType } from './source-type';
|
||||
export declare class StreamingSource implements BaseSource {
|
||||
private graph;
|
||||
private scene;
|
||||
private context;
|
||||
private element;
|
||||
private type;
|
||||
playing: boolean;
|
||||
private playOnAvailable;
|
||||
private node;
|
||||
private canPlay;
|
||||
private sceneNode;
|
||||
private gain;
|
||||
private position;
|
||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType);
|
||||
private init;
|
||||
play(when?: number, offset?: number, duration?: number): void;
|
||||
stop(): void;
|
||||
getVolume(): number;
|
||||
setVolume(value: number): void;
|
||||
getPlaybackRate(): number;
|
||||
setPlaybackRate(value: number): void;
|
||||
private createConnections;
|
||||
setPosition(x: number, y: number, z: number): void;
|
||||
destroy(): void;
|
||||
loop(value: boolean): void;
|
||||
fadeIn(time: number): void;
|
||||
fadeOut(time: number): void;
|
||||
}
|
99
framework/resonator/sources/streaming-source.js
Normal file
99
framework/resonator/sources/streaming-source.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import { SourceType } from './source-type';
|
||||
export class StreamingSource {
|
||||
constructor(graph, scene, context, element, type = SourceType.MasterSource) {
|
||||
this.graph = graph;
|
||||
this.scene = scene;
|
||||
this.context = context;
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
this.position = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
this.node = this.context.createMediaElementSource(this.element);
|
||||
this.gain = this.context.createGain();
|
||||
this.createConnections();
|
||||
this.element.addEventListener('canplay', (event) => {
|
||||
this.canPlay = true;
|
||||
if (this.playOnAvailable) {
|
||||
this.play();
|
||||
}
|
||||
});
|
||||
}
|
||||
play(when = 0, offset = 0, duration = 0) {
|
||||
if (this.canPlay) {
|
||||
this.element.play();
|
||||
}
|
||||
this.playOnAvailable = true;
|
||||
}
|
||||
stop() {
|
||||
this.element.pause();
|
||||
}
|
||||
getVolume() {
|
||||
return this.element.volume;
|
||||
}
|
||||
setVolume(value) {
|
||||
this.element.volume = value;
|
||||
}
|
||||
getPlaybackRate() {
|
||||
return this.element.playbackRate;
|
||||
}
|
||||
setPlaybackRate(value) {
|
||||
this.element.playbackRate = value;
|
||||
}
|
||||
createConnections() {
|
||||
switch (this.type) {
|
||||
case SourceType.WorldSource:
|
||||
if (!this.sceneNode) {
|
||||
this.sceneNode = this.scene.createSource();
|
||||
}
|
||||
this.node.connect(this.gain);
|
||||
this.gain.connect(this.sceneNode);
|
||||
break;
|
||||
default:
|
||||
this.node.connect(this.gain);
|
||||
this.graph.connectToMaster(this.gain);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setPosition(x, y, z) {
|
||||
this.position = {
|
||||
x,
|
||||
y,
|
||||
z
|
||||
};
|
||||
if (this.sceneNode)
|
||||
this.sceneNode.setPosition(x, y, z);
|
||||
}
|
||||
destroy() {
|
||||
this.stop();
|
||||
this.element = null;
|
||||
this.graph = null;
|
||||
this.context = null;
|
||||
this.node = null;
|
||||
this.sceneNode = null;
|
||||
this.scene = null;
|
||||
}
|
||||
loop(value) {
|
||||
this.element.loop = true;
|
||||
}
|
||||
fadeIn(time) {
|
||||
this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime);
|
||||
if (!this.node) {
|
||||
this.play();
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(this.getVolume(), this.context.getContext().currentTime + time);
|
||||
}
|
||||
fadeOut(time) {
|
||||
this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime);
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
||||
setTimeout(() => this.stop(), time * 1000);
|
||||
}
|
||||
}
|
40
framework/resonator/vendor/resonance-es6/attenuation.d.ts
vendored
Normal file
40
framework/resonator/vendor/resonance-es6/attenuation.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
export default Attenuation;
|
||||
/**
|
||||
* @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}.
|
||||
*/
|
||||
declare class Attenuation {
|
||||
constructor(context: any, options: any);
|
||||
minDistance: any;
|
||||
maxDistance: any;
|
||||
_gainNode: any;
|
||||
input: any;
|
||||
output: any;
|
||||
/**
|
||||
* Set distance from the listener.
|
||||
* @param {Number} distance Distance (in meters).
|
||||
*/
|
||||
setDistance(distance: number): void;
|
||||
/**
|
||||
* Set rolloff.
|
||||
* @param {string} rolloff
|
||||
* Rolloff model to use, chosen from options in
|
||||
* {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
|
||||
*/
|
||||
setRolloff(rolloff: string): void;
|
||||
_rolloff: string;
|
||||
}
|
151
framework/resonator/vendor/resonance-es6/attenuation.js
vendored
Normal file
151
framework/resonator/vendor/resonance-es6/attenuation.js
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @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 <bitllama@google.com>
|
||||
*/
|
||||
'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;
|
217
framework/resonator/vendor/resonance-es6/d.d.ts
vendored
Normal file
217
framework/resonator/vendor/resonance-es6/d.d.ts
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
declare module 'resonance-audio' {
|
||||
namespace ResonanceAudio {
|
||||
/** Options for constructing a new ResonanceAudio scene */
|
||||
interface Options {
|
||||
/** Desired ambisonic Order */
|
||||
ambisonicOrder?: number;
|
||||
/** The listener's initial position (in meters), where origin is the center of
|
||||
* the room */
|
||||
listenerPosition?: Float32Array;
|
||||
/** The listener's initial forward vector */
|
||||
listenerForward?: Float32Array;
|
||||
/** The listener's initial up vector */
|
||||
listenerUp?: Float32Array;
|
||||
/** Room dimensions (in meters) */
|
||||
dimensions?: Utils.RoomDimensions;
|
||||
/** Named acoustic materials per wall */
|
||||
materials?: Utils.RoomMaterials;
|
||||
/** (in meters/second) */
|
||||
speedOfSound?: number;
|
||||
}
|
||||
}
|
||||
/** Main class for managing sources, room and listener models */
|
||||
class ResonanceAudio {
|
||||
/** Binaurally-rendered stereo (2-channel) output */
|
||||
output: AudioNode;
|
||||
/** Ambisonic (multichannel) input */
|
||||
ambisonicInput: AudioNode;
|
||||
/** Ambisonic (multichannel) output */
|
||||
ambisonicOutput: AudioNode;
|
||||
constructor(context: AudioContext, options?: ResonanceAudio.Options);
|
||||
/**
|
||||
* Create a new source for the scene.
|
||||
* @param options
|
||||
* Options for constructing a new Source.
|
||||
*/
|
||||
createSource(options?: Source.Options): Source;
|
||||
/**
|
||||
* Set the scene's desired ambisonic order.
|
||||
* @param ambisonicOrder Desired ambisonic order.
|
||||
*/
|
||||
setAmbisonicOrder(ambisonicOrder: any): void;
|
||||
/**
|
||||
* Set the room's dimensions and wall materials.
|
||||
* @param dimensions Room dimensions (in meters).
|
||||
* @param materials Named acoustic materials per wall.
|
||||
*/
|
||||
setRoomProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void;
|
||||
/**
|
||||
* Set the listener's position (in meters), where origin is the center of
|
||||
* the room.
|
||||
*/
|
||||
setListenerPosition(x: number, y: number, z: number): any;
|
||||
/** Set the source's orientation using forward and up vectors. */
|
||||
setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/**
|
||||
* Set the listener's position and orientation using a Three.js Matrix4 object.
|
||||
* @param matrix
|
||||
* The Three.js Matrix4 object representing the listener's world transform.
|
||||
*/
|
||||
setListenerFromMatrix(matrix4: Float32Array): void;
|
||||
/**
|
||||
* Set the speed of sound.
|
||||
*/
|
||||
setSpeedOfSound(speedOfSound: number): void;
|
||||
}
|
||||
namespace Source {
|
||||
/** Options for constructing a new Source. */
|
||||
interface Options {
|
||||
/** The source's initial position (in meters), where origin is the center of
|
||||
* the room */
|
||||
position?: Float32Array;
|
||||
/** The source's initial forward vector */
|
||||
forward?: Float32Array;
|
||||
/** The source's initial up vector */
|
||||
up?: Float32Array;
|
||||
/** Min. distance (in meters) */
|
||||
minDistance?: number;
|
||||
/** Max. distance (in meters) */
|
||||
maxDistance?: number;
|
||||
/** Rolloff model to use */
|
||||
rolloff?: string;
|
||||
/** Input gain (linear) */
|
||||
gain?: number;
|
||||
/** Directivity alpha */
|
||||
alpha?: number;
|
||||
/** Directivity sharpness */
|
||||
sharpness?: number;
|
||||
/** Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source */
|
||||
sourceWidth?: number;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Source model to spatialize an audio buffer.
|
||||
*/
|
||||
class Source {
|
||||
constructor(scene: ResonanceAudio, options?: Source.Options);
|
||||
/** Mono (1-channel) input */
|
||||
input: AudioNode;
|
||||
/**
|
||||
* Set source's position (in meters), where origin is the center of
|
||||
* the room.
|
||||
*/
|
||||
setPosition(x: number, y: number, z: number): void;
|
||||
/** Set source's rolloff. */
|
||||
setRolloff(rolloff: string): void;
|
||||
/** Set source's minimum distance (in meters). */
|
||||
setMinDistance(minDistance: number): void;
|
||||
/** Set source's maximum distance (in meters). */
|
||||
setMaxDistance(maxDistance: number): void;
|
||||
/** Set source's gain (linear). */
|
||||
setGain(gain: number): void;
|
||||
/** Set the source's orientation using forward and up vectors. */
|
||||
setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/** Set source's position and orientation using a
|
||||
* Three.js modelViewMatrix object */
|
||||
setFromMatrix(matrix4: Float32Array): void;
|
||||
/** Set the source width (in degrees). Where 0 degrees is a point source and 360
|
||||
* degrees is an omnidirectional source */
|
||||
setSourceWidth(sourceWidth: number): void;
|
||||
/**
|
||||
* Set source's directivity pattern (defined by alpha), where 0 is an
|
||||
* omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
|
||||
* pattern. The sharpness of the pattern is increased exponentially
|
||||
* @param alpha
|
||||
* Determines directivity pattern (0 to 1).
|
||||
* @param sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf).
|
||||
*/
|
||||
setDirectivityPattern(alpha: number, sharpness: number): void;
|
||||
}
|
||||
namespace Room {
|
||||
interface Options {
|
||||
/** The listener's initial position (in meters), where origin is the center of
|
||||
* the room */
|
||||
listenerPosition?: Float32Array;
|
||||
/** Room dimensions (in meters) */
|
||||
dimensions?: Utils.RoomDimensions;
|
||||
/** Named acoustic materials per wall */
|
||||
materials?: Utils.RoomMaterials;
|
||||
/** (in meters/second) */
|
||||
speedOfSound?: number;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Model that manages early and late reflections using acoustic
|
||||
* properties and listener position relative to a rectangular room.
|
||||
*/
|
||||
class Room {
|
||||
constructor(context: AudioContext, options?: Room.Options);
|
||||
/**
|
||||
* Set the room's dimensions and wall materials.
|
||||
* @param dimensions Room dimensions (in meters)
|
||||
* @param materials Named acoustic materials per wall
|
||||
*/
|
||||
setProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void;
|
||||
/**
|
||||
* Set the listener's position (in meters), where origin is the center of
|
||||
* the room.
|
||||
*/
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
/**
|
||||
* Compute distance outside room of provided position (in meters).
|
||||
* @return
|
||||
* Distance outside room (in meters). Returns 0 if inside room.
|
||||
*/
|
||||
getDistanceOutsideRoom(x: number, y: number, z: number): number;
|
||||
}
|
||||
namespace Listener {
|
||||
interface Options {
|
||||
/** Desired ambisonic order */
|
||||
ambisonicOrder: number;
|
||||
/** Initial position (in meters), where origin is the center of
|
||||
* the room */
|
||||
position?: Float32Array;
|
||||
/** The listener's initial forward vector */
|
||||
forward?: Float32Array;
|
||||
/** The listener's initial up vector */
|
||||
up?: Float32Array;
|
||||
}
|
||||
}
|
||||
/** Listener model to spatialize sources in an environment */
|
||||
class Listener {
|
||||
/** Position (in meters) */
|
||||
position: Float32Array;
|
||||
/** Ambisonic (multichannel) input */
|
||||
input: AudioNode;
|
||||
/** Binaurally-rendered stereo (2-channel) output */
|
||||
output: AudioNode;
|
||||
/** Ambisonic (multichannel) output */
|
||||
ambisonicOutput: AudioNode;
|
||||
/**
|
||||
* Set the listener's orientation using forward and up vectors.
|
||||
*/
|
||||
setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/** Set listener's position and orientation using a
|
||||
* Three.js modelViewMatrix object */
|
||||
setFromMatrix(matrix4: Float32Array): void;
|
||||
}
|
||||
namespace Utils {
|
||||
/** Properties describing the geometry of a room. */
|
||||
interface RoomDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
depth: number;
|
||||
}
|
||||
/** Properties describing the wall materials */
|
||||
interface RoomMaterials {
|
||||
left: string;
|
||||
right: string;
|
||||
front: string;
|
||||
back: string;
|
||||
down: string;
|
||||
up: string;
|
||||
}
|
||||
}
|
||||
}
|
0
framework/resonator/vendor/resonance-es6/d.js
vendored
Normal file
0
framework/resonator/vendor/resonance-es6/d.js
vendored
Normal file
47
framework/resonator/vendor/resonance-es6/directivity.d.ts
vendored
Normal file
47
framework/resonator/vendor/resonance-es6/directivity.d.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
export default Directivity;
|
||||
/**
|
||||
* @class Directivity
|
||||
* @description Directivity/occlusion filter.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.alpha
|
||||
* Determines directivity pattern (0 to 1). See
|
||||
* {@link Directivity#setPattern setPattern} for more details. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
|
||||
* @param {Number} options.sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf). See
|
||||
* {@link Directivity#setPattern setPattern} for more details. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
*/
|
||||
declare class Directivity {
|
||||
constructor(context: any, options: any);
|
||||
_context: any;
|
||||
_lowpass: any;
|
||||
_cosTheta: number;
|
||||
input: any;
|
||||
output: any;
|
||||
/**
|
||||
* Compute the filter using the source's forward orientation and the listener's
|
||||
* position.
|
||||
* @param {Float32Array} forward The source's forward vector.
|
||||
* @param {Float32Array} direction The direction from the source to the
|
||||
* listener.
|
||||
*/
|
||||
computeAngle(forward: Float32Array, direction: Float32Array): void;
|
||||
/**
|
||||
* Set source's directivity pattern (defined by alpha), where 0 is an
|
||||
* omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
|
||||
* pattern. The sharpness of the pattern is increased exponenentially.
|
||||
* @param {Number} alpha
|
||||
* Determines directivity pattern (0 to 1).
|
||||
* @param {Number} sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf).
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
*/
|
||||
setPattern(alpha: number, sharpness: number): void;
|
||||
_alpha: number;
|
||||
_sharpness: number;
|
||||
}
|
117
framework/resonator/vendor/resonance-es6/directivity.js
vendored
Normal file
117
framework/resonator/vendor/resonance-es6/directivity.js
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @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 Directivity/occlusion filter.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* @class Directivity
|
||||
* @description Directivity/occlusion filter.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.alpha
|
||||
* Determines directivity pattern (0 to 1). See
|
||||
* {@link Directivity#setPattern setPattern} for more details. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
|
||||
* @param {Number} options.sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf). See
|
||||
* {@link Directivity#setPattern setPattern} for more details. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
*/
|
||||
class Directivity {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* Mono (1-channel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof Directivity
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Mono (1-channel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof Directivity
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.alpha == undefined) {
|
||||
options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA;
|
||||
}
|
||||
if (options.sharpness == undefined) {
|
||||
options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS;
|
||||
}
|
||||
// Create audio node.
|
||||
this._context = context;
|
||||
this._lowpass = context.createBiquadFilter();
|
||||
// Initialize filter coefficients.
|
||||
this._lowpass.type = 'lowpass';
|
||||
this._lowpass.Q.value = 0;
|
||||
this._lowpass.frequency.value = context.sampleRate * 0.5;
|
||||
this._cosTheta = 0;
|
||||
this.setPattern(options.alpha, options.sharpness);
|
||||
// Input/Output proxy.
|
||||
this.input = this._lowpass;
|
||||
this.output = this._lowpass;
|
||||
}
|
||||
/**
|
||||
* Compute the filter using the source's forward orientation and the listener's
|
||||
* position.
|
||||
* @param {Float32Array} forward The source's forward vector.
|
||||
* @param {Float32Array} direction The direction from the source to the
|
||||
* listener.
|
||||
*/
|
||||
computeAngle(forward, direction) {
|
||||
let forwardNorm = Utils.normalizeVector(forward);
|
||||
let directionNorm = Utils.normalizeVector(direction);
|
||||
let coeff = 1;
|
||||
if (this._alpha > Utils.EPSILON_FLOAT) {
|
||||
let cosTheta = forwardNorm[0] * directionNorm[0] +
|
||||
forwardNorm[1] * directionNorm[1] + forwardNorm[2] * directionNorm[2];
|
||||
coeff = (1 - this._alpha) + this._alpha * cosTheta;
|
||||
coeff = Math.pow(Math.abs(coeff), this._sharpness);
|
||||
}
|
||||
this._lowpass.frequency.value = this._context.sampleRate * 0.5 * coeff;
|
||||
}
|
||||
/**
|
||||
* Set source's directivity pattern (defined by alpha), where 0 is an
|
||||
* omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
|
||||
* pattern. The sharpness of the pattern is increased exponenentially.
|
||||
* @param {Number} alpha
|
||||
* Determines directivity pattern (0 to 1).
|
||||
* @param {Number} sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf).
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
*/
|
||||
setPattern(alpha, sharpness) {
|
||||
// Clamp and set values.
|
||||
this._alpha = Math.min(1, Math.max(0, alpha));
|
||||
this._sharpness = Math.max(1, sharpness);
|
||||
// Update angle calculation using new values.
|
||||
this.computeAngle([this._cosTheta * this._cosTheta, 0, 0], [1, 0, 0]);
|
||||
}
|
||||
}
|
||||
export default Directivity;
|
56
framework/resonator/vendor/resonance-es6/early-reflections.d.ts
vendored
Normal file
56
framework/resonator/vendor/resonance-es6/early-reflections.d.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
export default EarlyReflections;
|
||||
/**
|
||||
* @class EarlyReflections
|
||||
* @description Ray-tracing-based early reflections model.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Utils~RoomDimensions} options.dimensions
|
||||
* Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Object} options.coefficients
|
||||
* Frequency-independent reflection coeffs per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
* DEFAULT_REFLECTION_COEFFICIENTS}.
|
||||
* @param {Number} options.speedOfSound
|
||||
* (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND
|
||||
* DEFAULT_SPEED_OF_SOUND}.
|
||||
* @param {Float32Array} options.listenerPosition
|
||||
* (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
*/
|
||||
declare class EarlyReflections {
|
||||
constructor(context: any, options: any);
|
||||
speedOfSound: any;
|
||||
input: any;
|
||||
output: any;
|
||||
_lowpass: any;
|
||||
_delays: {};
|
||||
_gains: {};
|
||||
_inverters: {};
|
||||
_merger: any;
|
||||
_listenerPosition: any;
|
||||
/**
|
||||
* Set the listener's position (in meters),
|
||||
* where [0,0,0] is the center of the room.
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
*/
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
/**
|
||||
* Set the room's properties which determines the characteristics of
|
||||
* reflections.
|
||||
* @param {Utils~RoomDimensions} dimensions
|
||||
* Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Object} coefficients
|
||||
* Frequency-independent reflection coeffs per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
* DEFAULT_REFLECTION_COEFFICIENTS}.
|
||||
*/
|
||||
setRoomProperties(dimensions: any, coefficients: any): void;
|
||||
_coefficients: any;
|
||||
_halfDimensions: {};
|
||||
}
|
212
framework/resonator/vendor/resonance-es6/early-reflections.js
vendored
Normal file
212
framework/resonator/vendor/resonance-es6/early-reflections.js
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @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 Ray-tracing-based early reflections model.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* @class EarlyReflections
|
||||
* @description Ray-tracing-based early reflections model.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Utils~RoomDimensions} options.dimensions
|
||||
* Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Object} options.coefficients
|
||||
* Frequency-independent reflection coeffs per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
* DEFAULT_REFLECTION_COEFFICIENTS}.
|
||||
* @param {Number} options.speedOfSound
|
||||
* (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND
|
||||
* DEFAULT_SPEED_OF_SOUND}.
|
||||
* @param {Float32Array} options.listenerPosition
|
||||
* (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
*/
|
||||
class EarlyReflections {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* The room's speed of sound (in meters/second).
|
||||
* @member {Number} speedOfSound
|
||||
* @memberof EarlyReflections
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Mono (1-channel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof EarlyReflections
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* First-order ambisonic (4-channel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof EarlyReflections
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.speedOfSound == undefined) {
|
||||
options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
|
||||
}
|
||||
if (options.listenerPosition == undefined) {
|
||||
options.listenerPosition = Utils.DEFAULT_POSITION.slice();
|
||||
}
|
||||
if (options.coefficients == undefined) {
|
||||
options.coefficients = {};
|
||||
Object.assign(options.coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS);
|
||||
}
|
||||
// Assign room's speed of sound.
|
||||
this.speedOfSound = options.speedOfSound;
|
||||
// Create nodes.
|
||||
this.input = context.createGain();
|
||||
this.output = context.createGain();
|
||||
this._lowpass = context.createBiquadFilter();
|
||||
this._delays = {};
|
||||
this._gains = {}; // gainPerWall = (ReflectionCoeff / Attenuation)
|
||||
this._inverters = {}; // 3 of these are needed for right/back/down walls.
|
||||
this._merger = context.createChannelMerger(4); // First-order encoding only.
|
||||
// Connect audio graph for each wall reflection.
|
||||
for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
|
||||
if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
.hasOwnProperty(property)) {
|
||||
this._delays[property] =
|
||||
context.createDelay(Utils.MAX_DURATION);
|
||||
this._gains[property] = context.createGain();
|
||||
}
|
||||
}
|
||||
this._inverters.right = context.createGain();
|
||||
this._inverters.down = context.createGain();
|
||||
this._inverters.back = context.createGain();
|
||||
// Initialize lowpass filter.
|
||||
this._lowpass.type = 'lowpass';
|
||||
this._lowpass.frequency.value = Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY;
|
||||
this._lowpass.Q.value = 0;
|
||||
// Initialize encoder directions, set delay times and gains to 0.
|
||||
for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
|
||||
if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
.hasOwnProperty(property)) {
|
||||
this._delays[property].delayTime.value = 0;
|
||||
this._gains[property].gain.value = 0;
|
||||
}
|
||||
}
|
||||
// Initialize inverters for opposite walls ('right', 'down', 'back' only).
|
||||
this._inverters.right.gain.value = -1;
|
||||
this._inverters.down.gain.value = -1;
|
||||
this._inverters.back.gain.value = -1;
|
||||
// Connect nodes.
|
||||
this.input.connect(this._lowpass);
|
||||
for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
|
||||
if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
.hasOwnProperty(property)) {
|
||||
this._lowpass.connect(this._delays[property]);
|
||||
this._delays[property].connect(this._gains[property]);
|
||||
this._gains[property].connect(this._merger, 0, 0);
|
||||
}
|
||||
}
|
||||
// Connect gains to ambisonic channel output.
|
||||
// Left: [1 1 0 0]
|
||||
// Right: [1 -1 0 0]
|
||||
// Up: [1 0 1 0]
|
||||
// Down: [1 0 -1 0]
|
||||
// Front: [1 0 0 1]
|
||||
// Back: [1 0 0 -1]
|
||||
this._gains.left.connect(this._merger, 0, 1);
|
||||
this._gains.right.connect(this._inverters.right);
|
||||
this._inverters.right.connect(this._merger, 0, 1);
|
||||
this._gains.up.connect(this._merger, 0, 2);
|
||||
this._gains.down.connect(this._inverters.down);
|
||||
this._inverters.down.connect(this._merger, 0, 2);
|
||||
this._gains.front.connect(this._merger, 0, 3);
|
||||
this._gains.back.connect(this._inverters.back);
|
||||
this._inverters.back.connect(this._merger, 0, 3);
|
||||
this._merger.connect(this.output);
|
||||
// Initialize.
|
||||
this._listenerPosition = options.listenerPosition;
|
||||
this.setRoomProperties(options.dimensions, options.coefficients);
|
||||
}
|
||||
/**
|
||||
* Set the listener's position (in meters),
|
||||
* where [0,0,0] is the center of the room.
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
*/
|
||||
setListenerPosition(x, y, z) {
|
||||
// Assign listener position.
|
||||
this._listenerPosition = [x, y, z];
|
||||
// Determine distances to each wall.
|
||||
let distances = {
|
||||
left: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width + x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
right: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width - x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
front: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth + z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
back: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth - z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
down: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height + y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
up: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height - y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE,
|
||||
};
|
||||
// Assign delay & attenuation values using distances.
|
||||
for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
|
||||
if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
.hasOwnProperty(property)) {
|
||||
// Compute and assign delay (in seconds).
|
||||
let delayInSecs = distances[property] / this.speedOfSound;
|
||||
this._delays[property].delayTime.value = delayInSecs;
|
||||
// Compute and assign gain, uses logarithmic rolloff: "g = R / (d + 1)"
|
||||
let attenuation = this._coefficients[property] / distances[property];
|
||||
this._gains[property].gain.value = attenuation;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the room's properties which determines the characteristics of
|
||||
* reflections.
|
||||
* @param {Utils~RoomDimensions} dimensions
|
||||
* Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Object} coefficients
|
||||
* Frequency-independent reflection coeffs per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
* DEFAULT_REFLECTION_COEFFICIENTS}.
|
||||
*/
|
||||
setRoomProperties(dimensions, coefficients) {
|
||||
if (dimensions == undefined) {
|
||||
dimensions = {};
|
||||
Object.assign(dimensions, Utils.DEFAULT_ROOM_DIMENSIONS);
|
||||
}
|
||||
if (coefficients == undefined) {
|
||||
coefficients = {};
|
||||
Object.assign(coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS);
|
||||
}
|
||||
this._coefficients = coefficients;
|
||||
// Sanitize dimensions and store half-dimensions.
|
||||
this._halfDimensions = {};
|
||||
this._halfDimensions.width = dimensions.width * 0.5;
|
||||
this._halfDimensions.height = dimensions.height * 0.5;
|
||||
this._halfDimensions.depth = dimensions.depth * 0.5;
|
||||
// Update listener position with new room properties.
|
||||
this.setListenerPosition(this._listenerPosition[0], this._listenerPosition[1], this._listenerPosition[2]);
|
||||
}
|
||||
}
|
||||
export default EarlyReflections;
|
64
framework/resonator/vendor/resonance-es6/encoder.d.ts
vendored
Normal file
64
framework/resonator/vendor/resonance-es6/encoder.d.ts
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
export default Encoder;
|
||||
/**
|
||||
* @class Encoder
|
||||
* @description Spatially encodes input using weighted spherical harmonics.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.ambisonicOrder
|
||||
* Desired ambisonic order. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
|
||||
* @param {Number} options.azimuth
|
||||
* Azimuth (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
|
||||
* @param {Number} options.elevation
|
||||
* Elevation (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
|
||||
* @param {Number} options.sourceWidth
|
||||
* Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
|
||||
*/
|
||||
declare class Encoder {
|
||||
constructor(context: any, options: any);
|
||||
_context: any;
|
||||
input: any;
|
||||
_channelGain: any[];
|
||||
_merger: any;
|
||||
output: any;
|
||||
_azimuth: any;
|
||||
_elevation: any;
|
||||
/**
|
||||
* Set the desired ambisonic order.
|
||||
* @param {Number} ambisonicOrder Desired ambisonic order.
|
||||
*/
|
||||
setAmbisonicOrder(ambisonicOrder: number): void;
|
||||
_ambisonicOrder: number;
|
||||
/**
|
||||
* Set the direction of the encoded source signal.
|
||||
* @param {Number} azimuth
|
||||
* Azimuth (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
|
||||
* @param {Number} elevation
|
||||
* Elevation (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
|
||||
*/
|
||||
setDirection(azimuth: number, elevation: number): void;
|
||||
/**
|
||||
* Set the source width (in degrees). Where 0 degrees is a point source and 360
|
||||
* degrees is an omnidirectional source.
|
||||
* @param {Number} sourceWidth (in degrees).
|
||||
*/
|
||||
setSourceWidth(sourceWidth: number): void;
|
||||
_spreadIndex: number;
|
||||
}
|
||||
declare namespace Encoder {
|
||||
/**
|
||||
* Validate the provided ambisonic order.
|
||||
* @param {Number} ambisonicOrder Desired ambisonic order.
|
||||
* @return {Number} Validated/adjusted ambisonic order.
|
||||
* @private
|
||||
*/
|
||||
function validateAmbisonicOrder(ambisonicOrder: number): number;
|
||||
}
|
194
framework/resonator/vendor/resonance-es6/encoder.js
vendored
Normal file
194
framework/resonator/vendor/resonance-es6/encoder.js
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @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 Spatially encodes input using weighted spherical harmonics.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Tables from './tables.js';
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* @class Encoder
|
||||
* @description Spatially encodes input using weighted spherical harmonics.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.ambisonicOrder
|
||||
* Desired ambisonic order. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
|
||||
* @param {Number} options.azimuth
|
||||
* Azimuth (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
|
||||
* @param {Number} options.elevation
|
||||
* Elevation (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
|
||||
* @param {Number} options.sourceWidth
|
||||
* Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
|
||||
*/
|
||||
class Encoder {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* Mono (1-channel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof Encoder
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Ambisonic (multichannel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof Encoder
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.ambisonicOrder == undefined) {
|
||||
options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
|
||||
}
|
||||
if (options.azimuth == undefined) {
|
||||
options.azimuth = Utils.DEFAULT_AZIMUTH;
|
||||
}
|
||||
if (options.elevation == undefined) {
|
||||
options.elevation = Utils.DEFAULT_ELEVATION;
|
||||
}
|
||||
if (options.sourceWidth == undefined) {
|
||||
options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH;
|
||||
}
|
||||
this._context = context;
|
||||
// Create I/O nodes.
|
||||
this.input = context.createGain();
|
||||
this._channelGain = [];
|
||||
this._merger = undefined;
|
||||
this.output = context.createGain();
|
||||
// Set initial order, angle and source width.
|
||||
this.setAmbisonicOrder(options.ambisonicOrder);
|
||||
this._azimuth = options.azimuth;
|
||||
this._elevation = options.elevation;
|
||||
this.setSourceWidth(options.sourceWidth);
|
||||
}
|
||||
/**
|
||||
* Set the desired ambisonic order.
|
||||
* @param {Number} ambisonicOrder Desired ambisonic order.
|
||||
*/
|
||||
setAmbisonicOrder(ambisonicOrder) {
|
||||
this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder);
|
||||
this.input.disconnect();
|
||||
for (let i = 0; i < this._channelGain.length; i++) {
|
||||
this._channelGain[i].disconnect();
|
||||
}
|
||||
if (this._merger != undefined) {
|
||||
this._merger.disconnect();
|
||||
}
|
||||
delete this._channelGain;
|
||||
delete this._merger;
|
||||
// Create audio graph.
|
||||
let numChannels = (this._ambisonicOrder + 1) * (this._ambisonicOrder + 1);
|
||||
this._merger = this._context.createChannelMerger(numChannels);
|
||||
this._channelGain = new Array(numChannels);
|
||||
for (let i = 0; i < numChannels; i++) {
|
||||
this._channelGain[i] = this._context.createGain();
|
||||
this.input.connect(this._channelGain[i]);
|
||||
this._channelGain[i].connect(this._merger, 0, i);
|
||||
}
|
||||
this._merger.connect(this.output);
|
||||
}
|
||||
/**
|
||||
* Set the direction of the encoded source signal.
|
||||
* @param {Number} azimuth
|
||||
* Azimuth (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}.
|
||||
* @param {Number} elevation
|
||||
* Elevation (in degrees). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}.
|
||||
*/
|
||||
setDirection(azimuth, elevation) {
|
||||
// Format input direction to nearest indices.
|
||||
if (azimuth == undefined || isNaN(azimuth)) {
|
||||
azimuth = Utils.DEFAULT_AZIMUTH;
|
||||
}
|
||||
if (elevation == undefined || isNaN(elevation)) {
|
||||
elevation = Utils.DEFAULT_ELEVATION;
|
||||
}
|
||||
// Store the formatted input (for updating source width).
|
||||
this._azimuth = azimuth;
|
||||
this._elevation = elevation;
|
||||
// Format direction for index lookups.
|
||||
azimuth = Math.round(azimuth % 360);
|
||||
if (azimuth < 0) {
|
||||
azimuth += 360;
|
||||
}
|
||||
elevation = Math.round(Math.min(90, Math.max(-90, elevation))) + 90;
|
||||
// Assign gains to each output.
|
||||
this._channelGain[0].gain.value = Tables.MAX_RE_WEIGHTS[this._spreadIndex][0];
|
||||
for (let i = 1; i <= this._ambisonicOrder; i++) {
|
||||
let degreeWeight = Tables.MAX_RE_WEIGHTS[this._spreadIndex][i];
|
||||
for (let j = -i; j <= i; j++) {
|
||||
let acnChannel = (i * i) + i + j;
|
||||
let elevationIndex = i * (i + 1) / 2 + Math.abs(j) - 1;
|
||||
let val = Tables.SPHERICAL_HARMONICS[1][elevation][elevationIndex];
|
||||
if (j != 0) {
|
||||
let azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j - 1;
|
||||
if (j < 0) {
|
||||
azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j;
|
||||
}
|
||||
val *= Tables.SPHERICAL_HARMONICS[0][azimuth][azimuthIndex];
|
||||
}
|
||||
this._channelGain[acnChannel].gain.value = val * degreeWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the source width (in degrees). Where 0 degrees is a point source and 360
|
||||
* degrees is an omnidirectional source.
|
||||
* @param {Number} sourceWidth (in degrees).
|
||||
*/
|
||||
setSourceWidth(sourceWidth) {
|
||||
// The MAX_RE_WEIGHTS is a 360 x (Tables.SPHERICAL_HARMONICS_MAX_ORDER+1)
|
||||
// size table.
|
||||
this._spreadIndex = Math.min(359, Math.max(0, Math.round(sourceWidth)));
|
||||
this.setDirection(this._azimuth, this._elevation);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Validate the provided ambisonic order.
|
||||
* @param {Number} ambisonicOrder Desired ambisonic order.
|
||||
* @return {Number} Validated/adjusted ambisonic order.
|
||||
* @private
|
||||
*/
|
||||
Encoder.validateAmbisonicOrder = ambisonicOrder => {
|
||||
if (isNaN(ambisonicOrder) || ambisonicOrder == undefined) {
|
||||
Utils.log('Error: Invalid ambisonic order', options.ambisonicOrder, '\nUsing ambisonicOrder=1 instead.');
|
||||
ambisonicOrder = 1;
|
||||
}
|
||||
else if (ambisonicOrder < 1) {
|
||||
Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Min order is 1)', '\nUsing min order instead.');
|
||||
ambisonicOrder = 1;
|
||||
}
|
||||
else if (ambisonicOrder > Tables.SPHERICAL_HARMONICS_MAX_ORDER) {
|
||||
Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Max order is', Tables.SPHERICAL_HARMONICS_MAX_ORDER, ')\nUsing max order instead.');
|
||||
options.ambisonicOrder = Tables.SPHERICAL_HARMONICS_MAX_ORDER;
|
||||
}
|
||||
return ambisonicOrder;
|
||||
};
|
||||
export default Encoder;
|
42
framework/resonator/vendor/resonance-es6/late-reflections.d.ts
vendored
Normal file
42
framework/resonator/vendor/resonance-es6/late-reflections.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
export default LateReflections;
|
||||
/**
|
||||
* @class LateReflections
|
||||
* @description Late-reflections reverberation filter for Ambisonic content.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Array} options.durations
|
||||
* Multiband RT60 durations (in seconds) for each frequency band, listed as
|
||||
* {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
|
||||
* FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}.
|
||||
* @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}.
|
||||
* @param {Number} options.gain Output gain (linear). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}.
|
||||
* @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency
|
||||
* band. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}.
|
||||
* @param {Number} options.tailonset Length (in milliseconds) of impulse
|
||||
* response to apply a half-Hann window. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}.
|
||||
*/
|
||||
declare class LateReflections {
|
||||
constructor(context: any, options: any);
|
||||
_bandwidthCoeff: number;
|
||||
_tailonsetSamples: number;
|
||||
_context: any;
|
||||
input: any;
|
||||
_predelay: any;
|
||||
_convolver: any;
|
||||
output: any;
|
||||
/**
|
||||
* Re-compute a new impulse response by providing Multiband RT60 durations.
|
||||
* @param {Array} durations
|
||||
* Multiband RT60 durations (in seconds) for each frequency band, listed as
|
||||
* {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
|
||||
* DEFAULT_REVERB_FREQUENCY_BANDS}.
|
||||
*/
|
||||
setDurations(durations: any[]): void;
|
||||
}
|
187
framework/resonator/vendor/resonance-es6/late-reflections.js
vendored
Normal file
187
framework/resonator/vendor/resonance-es6/late-reflections.js
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* @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 Late reverberation filter for Ambisonic content.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* @class LateReflections
|
||||
* @description Late-reflections reverberation filter for Ambisonic content.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Array} options.durations
|
||||
* Multiband RT60 durations (in seconds) for each frequency band, listed as
|
||||
* {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
|
||||
* FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}.
|
||||
* @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}.
|
||||
* @param {Number} options.gain Output gain (linear). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}.
|
||||
* @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency
|
||||
* band. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}.
|
||||
* @param {Number} options.tailonset Length (in milliseconds) of impulse
|
||||
* response to apply a half-Hann window. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}.
|
||||
*/
|
||||
class LateReflections {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* Mono (1-channel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof LateReflections
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Mono (1-channel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof LateReflections
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.durations == undefined) {
|
||||
options.durations = Utils.DEFAULT_REVERB_DURATIONS.slice();
|
||||
}
|
||||
if (options.predelay == undefined) {
|
||||
options.predelay = Utils.DEFAULT_REVERB_PREDELAY;
|
||||
}
|
||||
if (options.gain == undefined) {
|
||||
options.gain = Utils.DEFAULT_REVERB_GAIN;
|
||||
}
|
||||
if (options.bandwidth == undefined) {
|
||||
options.bandwidth = Utils.DEFAULT_REVERB_BANDWIDTH;
|
||||
}
|
||||
if (options.tailonset == undefined) {
|
||||
options.tailonset = Utils.DEFAULT_REVERB_TAIL_ONSET;
|
||||
}
|
||||
// Assign pre-computed variables.
|
||||
let delaySecs = options.predelay / 1000;
|
||||
this._bandwidthCoeff = options.bandwidth * Utils.LOG2_DIV2;
|
||||
this._tailonsetSamples = options.tailonset / 1000;
|
||||
// Create nodes.
|
||||
this._context = context;
|
||||
this.input = context.createGain();
|
||||
this._predelay = context.createDelay(delaySecs);
|
||||
this._convolver = context.createConvolver();
|
||||
this.output = context.createGain();
|
||||
// Set reverb attenuation.
|
||||
this.output.gain.value = options.gain;
|
||||
// Disable normalization.
|
||||
this._convolver.normalize = false;
|
||||
// Connect nodes.
|
||||
this.input.connect(this._predelay);
|
||||
this._predelay.connect(this._convolver);
|
||||
this._convolver.connect(this.output);
|
||||
// Compute IR using RT60 values.
|
||||
this.setDurations(options.durations);
|
||||
}
|
||||
/**
|
||||
* Re-compute a new impulse response by providing Multiband RT60 durations.
|
||||
* @param {Array} durations
|
||||
* Multiband RT60 durations (in seconds) for each frequency band, listed as
|
||||
* {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS
|
||||
* DEFAULT_REVERB_FREQUENCY_BANDS}.
|
||||
*/
|
||||
setDurations(durations) {
|
||||
if (durations.length !== Utils.NUMBER_REVERB_FREQUENCY_BANDS) {
|
||||
Utils.log('Warning: invalid number of RT60 values provided to reverb.');
|
||||
return;
|
||||
}
|
||||
// Compute impulse response.
|
||||
let durationsSamples = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
|
||||
let sampleRate = this._context.sampleRate;
|
||||
for (let i = 0; i < durations.length; i++) {
|
||||
// Clamp within suitable range.
|
||||
durations[i] =
|
||||
Math.max(0, Math.min(Utils.DEFAULT_REVERB_MAX_DURATION, durations[i]));
|
||||
// Convert seconds to samples.
|
||||
durationsSamples[i] = Math.round(durations[i] * sampleRate *
|
||||
Utils.DEFAULT_REVERB_DURATION_MULTIPLIER);
|
||||
}
|
||||
;
|
||||
// Determine max RT60 length in samples.
|
||||
let durationsSamplesMax = 0;
|
||||
for (let i = 0; i < durationsSamples.length; i++) {
|
||||
if (durationsSamples[i] > durationsSamplesMax) {
|
||||
durationsSamplesMax = durationsSamples[i];
|
||||
}
|
||||
}
|
||||
// Skip this step if there is no reverberation to compute.
|
||||
if (durationsSamplesMax < 1) {
|
||||
durationsSamplesMax = 1;
|
||||
}
|
||||
// Create impulse response buffer.
|
||||
let buffer = this._context.createBuffer(1, durationsSamplesMax, sampleRate);
|
||||
let bufferData = buffer.getChannelData(0);
|
||||
// Create noise signal (computed once, referenced in each band's routine).
|
||||
let noiseSignal = new Float32Array(durationsSamplesMax);
|
||||
for (let i = 0; i < durationsSamplesMax; i++) {
|
||||
noiseSignal[i] = Math.random() * 2 - 1;
|
||||
}
|
||||
// Compute the decay rate per-band and filter the decaying noise signal.
|
||||
for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) {
|
||||
// Compute decay rate.
|
||||
let decayRate = -Utils.LOG1000 / durationsSamples[i];
|
||||
// Construct a standard one-zero, two-pole bandpass filter:
|
||||
// H(z) = (b0 * z^0 + b1 * z^-1 + b2 * z^-2) / (1 + a1 * z^-1 + a2 * z^-2)
|
||||
let omega = Utils.TWO_PI *
|
||||
Utils.DEFAULT_REVERB_FREQUENCY_BANDS[i] / sampleRate;
|
||||
let sinOmega = Math.sin(omega);
|
||||
let alpha = sinOmega * Math.sinh(this._bandwidthCoeff * omega / sinOmega);
|
||||
let a0CoeffReciprocal = 1 / (1 + alpha);
|
||||
let b0Coeff = alpha * a0CoeffReciprocal;
|
||||
let a1Coeff = -2 * Math.cos(omega) * a0CoeffReciprocal;
|
||||
let a2Coeff = (1 - alpha) * a0CoeffReciprocal;
|
||||
// We optimize since b2 = -b0, b1 = 0.
|
||||
// Update equation for two-pole bandpass filter:
|
||||
// u[n] = x[n] - a1 * x[n-1] - a2 * x[n-2]
|
||||
// y[n] = b0 * (u[n] - u[n-2])
|
||||
let um1 = 0;
|
||||
let um2 = 0;
|
||||
for (let j = 0; j < durationsSamples[i]; j++) {
|
||||
// Exponentially-decaying white noise.
|
||||
let x = noiseSignal[j] * Math.exp(decayRate * j);
|
||||
// Filter signal with bandpass filter and add to output.
|
||||
let u = x - a1Coeff * um1 - a2Coeff * um2;
|
||||
bufferData[j] += b0Coeff * (u - um2);
|
||||
// Update coefficients.
|
||||
um2 = um1;
|
||||
um1 = u;
|
||||
}
|
||||
}
|
||||
// Create and apply half of a Hann window to the beginning of the
|
||||
// impulse response.
|
||||
let halfHannLength = Math.round(this._tailonsetSamples);
|
||||
for (let i = 0; i < Math.min(bufferData.length, halfHannLength); i++) {
|
||||
let halfHann = 0.5 * (1 - Math.cos(Utils.TWO_PI * i / (2 * halfHannLength - 1)));
|
||||
bufferData[i] *= halfHann;
|
||||
}
|
||||
this._convolver.buffer = buffer;
|
||||
}
|
||||
}
|
||||
export default LateReflections;
|
49
framework/resonator/vendor/resonance-es6/listener.d.ts
vendored
Normal file
49
framework/resonator/vendor/resonance-es6/listener.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
export default Listener;
|
||||
/**
|
||||
* @class Listener
|
||||
* @description Listener model to spatialize sources in an environment.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.ambisonicOrder
|
||||
* Desired ambisonic order. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
|
||||
* @param {Float32Array} options.position
|
||||
* Initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @param {Float32Array} options.forward
|
||||
* The listener's initial forward vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
* @param {Float32Array} options.up
|
||||
* The listener's initial up vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
*/
|
||||
declare class Listener {
|
||||
constructor(context: any, options: any);
|
||||
position: Float32Array;
|
||||
_tempMatrix3: Float32Array;
|
||||
_ambisonicOrder: number;
|
||||
_context: any;
|
||||
_renderer: any;
|
||||
input: any;
|
||||
output: any;
|
||||
ambisonicOutput: any;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/**
|
||||
* Set the listener's position and orientation using a Three.js Matrix4 object.
|
||||
* @param {Object} matrix4
|
||||
* The Three.js Matrix4 object representing the listener's world transform.
|
||||
*/
|
||||
setFromMatrix(matrix4: any): void;
|
||||
}
|
168
framework/resonator/vendor/resonance-es6/listener.js
vendored
Normal file
168
framework/resonator/vendor/resonance-es6/listener.js
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @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 Listener model to spatialize sources in an environment.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Omnitone from 'omnitone/build/omnitone.esm';
|
||||
import Encoder from './encoder.js';
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* @class Listener
|
||||
* @description Listener model to spatialize sources in an environment.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Number} options.ambisonicOrder
|
||||
* Desired ambisonic order. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
|
||||
* @param {Float32Array} options.position
|
||||
* Initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @param {Float32Array} options.forward
|
||||
* The listener's initial forward vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
* @param {Float32Array} options.up
|
||||
* The listener's initial up vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
*/
|
||||
class Listener {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* Position (in meters).
|
||||
* @member {Float32Array} position
|
||||
* @memberof Listener
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Ambisonic (multichannel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof Listener
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Binaurally-rendered stereo (2-channel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof Listener
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Ambisonic (multichannel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} ambisonicOutput
|
||||
* @memberof Listener
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.ambisonicOrder == undefined) {
|
||||
options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER;
|
||||
}
|
||||
if (options.position == undefined) {
|
||||
options.position = Utils.DEFAULT_POSITION.slice();
|
||||
}
|
||||
if (options.forward == undefined) {
|
||||
options.forward = Utils.DEFAULT_FORWARD.slice();
|
||||
}
|
||||
if (options.up == undefined) {
|
||||
options.up = Utils.DEFAULT_UP.slice();
|
||||
}
|
||||
// Member variables.
|
||||
this.position = new Float32Array(3);
|
||||
this._tempMatrix3 = new Float32Array(9);
|
||||
// Select the appropriate HRIR filters using 2-channel chunks since
|
||||
// multichannel audio is not yet supported by a majority of browsers.
|
||||
this._ambisonicOrder =
|
||||
Encoder.validateAmbisonicOrder(options.ambisonicOrder);
|
||||
// Create audio nodes.
|
||||
this._context = context;
|
||||
if (this._ambisonicOrder == 1) {
|
||||
this._renderer = Omnitone.createFOARenderer(context, {});
|
||||
}
|
||||
else if (this._ambisonicOrder > 1) {
|
||||
this._renderer = Omnitone.createHOARenderer(context, {
|
||||
ambisonicOrder: this._ambisonicOrder,
|
||||
});
|
||||
}
|
||||
// These nodes are created in order to safely asynchronously load Omnitone
|
||||
// while the rest of the scene is being created.
|
||||
this.input = context.createGain();
|
||||
this.output = context.createGain();
|
||||
this.ambisonicOutput = context.createGain();
|
||||
// Initialize Omnitone (async) and connect to audio graph when complete.
|
||||
let that = this;
|
||||
this._renderer.initialize().then(() => {
|
||||
// Connect pre-rotated soundfield to renderer.
|
||||
that.input.connect(that._renderer.input);
|
||||
// Connect rotated soundfield to ambisonic output.
|
||||
if (that._ambisonicOrder > 1) {
|
||||
that._renderer._hoaRotator.output.connect(that.ambisonicOutput);
|
||||
}
|
||||
else {
|
||||
that._renderer._foaRotator.output.connect(that.ambisonicOutput);
|
||||
}
|
||||
// Connect binaurally-rendered soundfield to binaural output.
|
||||
that._renderer.output.connect(that.output);
|
||||
});
|
||||
// Set orientation and update rotation matrix accordingly.
|
||||
this.setOrientation(options.forward[0], options.forward[1], options.forward[2], options.up[0], options.up[1], options.up[2]);
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
|
||||
let right = Utils.crossProduct([forwardX, forwardY, forwardZ], [upX, upY, upZ]);
|
||||
this._tempMatrix3[0] = right[0];
|
||||
this._tempMatrix3[1] = right[1];
|
||||
this._tempMatrix3[2] = right[2];
|
||||
this._tempMatrix3[3] = upX;
|
||||
this._tempMatrix3[4] = upY;
|
||||
this._tempMatrix3[5] = upZ;
|
||||
this._tempMatrix3[6] = forwardX;
|
||||
this._tempMatrix3[7] = forwardY;
|
||||
this._tempMatrix3[8] = forwardZ;
|
||||
this._renderer.setRotationMatrix3(this._tempMatrix3);
|
||||
}
|
||||
/**
|
||||
* Set the listener's position and orientation using a Three.js Matrix4 object.
|
||||
* @param {Object} matrix4
|
||||
* The Three.js Matrix4 object representing the listener's world transform.
|
||||
*/
|
||||
setFromMatrix(matrix4) {
|
||||
// Update ambisonic rotation matrix internally.
|
||||
this._renderer.setRotationMatrix4(matrix4.elements);
|
||||
// Extract position from matrix.
|
||||
this.position[0] = matrix4.elements[12];
|
||||
this.position[1] = matrix4.elements[13];
|
||||
this.position[2] = matrix4.elements[14];
|
||||
}
|
||||
}
|
||||
export default Listener;
|
2
framework/resonator/vendor/resonance-es6/main.d.ts
vendored
Normal file
2
framework/resonator/vendor/resonance-es6/main.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export default ResonanceAudio;
|
||||
import ResonanceAudio from "./resonance-audio";
|
23
framework/resonator/vendor/resonance-es6/main.js
vendored
Normal file
23
framework/resonator/vendor/resonance-es6/main.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @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 Primary namespace for ResonanceAudio library.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
import ResonanceAudio from './resonance-audio';
|
||||
// Main module.
|
||||
export default ResonanceAudio;
|
130
framework/resonator/vendor/resonance-es6/resonance-audio.d.ts
vendored
Normal file
130
framework/resonator/vendor/resonance-es6/resonance-audio.d.ts
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
export default ResonanceAudio;
|
||||
/**
|
||||
* ~ResonanceAudioOptions
|
||||
*/
|
||||
export type ResonanceAudio = {
|
||||
/**
|
||||
* Desired ambisonic Order. Defaults to
|
||||
* {@link Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}.
|
||||
*/
|
||||
ambisonicOrder: number;
|
||||
/**
|
||||
* The listener's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
*/
|
||||
listenerPosition: Float32Array;
|
||||
/**
|
||||
* The listener's initial forward vector.
|
||||
* Defaults to {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
*/
|
||||
listenerForward: Float32Array;
|
||||
/**
|
||||
* The listener's initial up vector.
|
||||
* Defaults to {@link Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
*/
|
||||
listenerUp: Float32Array;
|
||||
/**
|
||||
* ~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
|
||||
* {@link Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
*/
|
||||
"": Utils;
|
||||
/**
|
||||
* (in meters/second). Defaults to
|
||||
* {@link Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
|
||||
*/
|
||||
speedOfSound: number;
|
||||
};
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
declare class ResonanceAudio {
|
||||
constructor(context: any, options: any);
|
||||
_ambisonicOrder: number;
|
||||
_sources: any[];
|
||||
_room: Room;
|
||||
_listener: Listener;
|
||||
_context: any;
|
||||
output: any;
|
||||
ambisonicOutput: any;
|
||||
ambisonicInput: any;
|
||||
/**
|
||||
* Create a new source for the scene.
|
||||
* @param {Source~SourceOptions} options
|
||||
* Options for constructing a new Source.
|
||||
* @return {Source}
|
||||
*/
|
||||
createSource(options: any): Source;
|
||||
/**
|
||||
* Set the scene's desired ambisonic order.
|
||||
* @param {Number} ambisonicOrder Desired ambisonic order.
|
||||
*/
|
||||
setAmbisonicOrder(ambisonicOrder: number): void;
|
||||
/**
|
||||
* 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: any, materials: any): void;
|
||||
/**
|
||||
* 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: number, y: number, z: number): void;
|
||||
/**
|
||||
* 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: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/**
|
||||
* 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: any): void;
|
||||
/**
|
||||
* Set the speed of sound.
|
||||
* @param {Number} speedOfSound
|
||||
*/
|
||||
setSpeedOfSound(speedOfSound: number): void;
|
||||
}
|
||||
import Utils from "./utils.js";
|
||||
import Room from "./room.js";
|
||||
import Listener from "./listener.js";
|
||||
import Source from "./source.js";
|
213
framework/resonator/vendor/resonance-es6/resonance-audio.js
vendored
Normal file
213
framework/resonator/vendor/resonance-es6/resonance-audio.js
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* @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;
|
55
framework/resonator/vendor/resonance-es6/room.d.ts
vendored
Normal file
55
framework/resonator/vendor/resonance-es6/room.d.ts
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
export default Room;
|
||||
/**
|
||||
* @class Room
|
||||
* @description Model that manages early and late reflections using acoustic
|
||||
* properties and listener position relative to a rectangular room.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Float32Array} options.listenerPosition
|
||||
* The listener's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall.
|
||||
* Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
|
||||
* @param {Number} options.speedOfSound
|
||||
* (in meters/second). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
|
||||
*/
|
||||
declare class Room {
|
||||
constructor(context: any, options: any);
|
||||
early: EarlyReflections;
|
||||
late: LateReflections;
|
||||
speedOfSound: any;
|
||||
output: any;
|
||||
_merger: any;
|
||||
/**
|
||||
* Set the room's dimensions and wall materials.
|
||||
* @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
|
||||
*/
|
||||
setProperties(dimensions: any, materials: any): void;
|
||||
/**
|
||||
* 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: number, y: number, z: number): void;
|
||||
/**
|
||||
* Compute distance outside room of provided position (in meters).
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
* @return {Number}
|
||||
* Distance outside room (in meters). Returns 0 if inside room.
|
||||
*/
|
||||
getDistanceOutsideRoom(x: number, y: number, z: number): number;
|
||||
}
|
||||
import EarlyReflections from "./early-reflections.js";
|
||||
import LateReflections from "./late-reflections.js";
|
300
framework/resonator/vendor/resonance-es6/room.js
vendored
Normal file
300
framework/resonator/vendor/resonance-es6/room.js
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* @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 Complete room model with early and late reflections.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import LateReflections from './late-reflections.js';
|
||||
import EarlyReflections from './early-reflections.js';
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* Generate absorption coefficients from material names.
|
||||
* @param {Object} materials
|
||||
* @return {Object}
|
||||
*/
|
||||
function _getCoefficientsFromMaterials(materials) {
|
||||
// Initialize coefficients to use defaults.
|
||||
let coefficients = {};
|
||||
for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
|
||||
if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property)) {
|
||||
coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]];
|
||||
}
|
||||
}
|
||||
// Sanitize materials.
|
||||
if (materials == undefined) {
|
||||
materials = {};
|
||||
Object.assign(materials, Utils.DEFAULT_ROOM_MATERIALS);
|
||||
}
|
||||
// Assign coefficients using provided materials.
|
||||
for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
|
||||
if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property) &&
|
||||
materials.hasOwnProperty(property)) {
|
||||
if (materials[property] in Utils.ROOM_MATERIAL_COEFFICIENTS) {
|
||||
coefficients[property] =
|
||||
Utils.ROOM_MATERIAL_COEFFICIENTS[materials[property]];
|
||||
}
|
||||
else {
|
||||
Utils.log('Material \"' + materials[property] + '\" on wall \"' +
|
||||
property + '\" not found. Using \"' +
|
||||
Utils.DEFAULT_ROOM_MATERIALS[property] + '\".');
|
||||
}
|
||||
}
|
||||
else {
|
||||
Utils.log('Wall \"' + property + '\" is not defined. Default used.');
|
||||
}
|
||||
}
|
||||
return coefficients;
|
||||
}
|
||||
/**
|
||||
* Sanitize coefficients.
|
||||
* @param {Object} coefficients
|
||||
* @return {Object}
|
||||
*/
|
||||
function _sanitizeCoefficients(coefficients) {
|
||||
if (coefficients == undefined) {
|
||||
coefficients = {};
|
||||
}
|
||||
for (let property in Utils.DEFAULT_ROOM_MATERIALS) {
|
||||
if (!(coefficients.hasOwnProperty(property))) {
|
||||
// If element is not present, use default coefficients.
|
||||
coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]];
|
||||
}
|
||||
}
|
||||
return coefficients;
|
||||
}
|
||||
/**
|
||||
* Sanitize dimensions.
|
||||
* @param {Utils~RoomDimensions} dimensions
|
||||
* @return {Utils~RoomDimensions}
|
||||
*/
|
||||
function _sanitizeDimensions(dimensions) {
|
||||
if (dimensions == undefined) {
|
||||
dimensions = {};
|
||||
}
|
||||
for (let property in Utils.DEFAULT_ROOM_DIMENSIONS) {
|
||||
if (!(dimensions.hasOwnProperty(property))) {
|
||||
dimensions[property] = Utils.DEFAULT_ROOM_DIMENSIONS[property];
|
||||
}
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
/**
|
||||
* Compute frequency-dependent reverb durations.
|
||||
* @param {Utils~RoomDimensions} dimensions
|
||||
* @param {Object} coefficients
|
||||
* @param {Number} speedOfSound
|
||||
* @return {Array}
|
||||
*/
|
||||
function _getDurationsFromProperties(dimensions, coefficients, speedOfSound) {
|
||||
let durations = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
|
||||
// Sanitize inputs.
|
||||
dimensions = _sanitizeDimensions(dimensions);
|
||||
coefficients = _sanitizeCoefficients(coefficients);
|
||||
if (speedOfSound == undefined) {
|
||||
speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND;
|
||||
}
|
||||
// Acoustic constant.
|
||||
let k = Utils.TWENTY_FOUR_LOG10 / speedOfSound;
|
||||
// Compute volume, skip if room is not present.
|
||||
let volume = dimensions.width * dimensions.height * dimensions.depth;
|
||||
if (volume < Utils.ROOM_MIN_VOLUME) {
|
||||
return durations;
|
||||
}
|
||||
// Room surface area.
|
||||
let leftRightArea = dimensions.width * dimensions.height;
|
||||
let floorCeilingArea = dimensions.width * dimensions.depth;
|
||||
let frontBackArea = dimensions.depth * dimensions.height;
|
||||
let totalArea = 2 * (leftRightArea + floorCeilingArea + frontBackArea);
|
||||
for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) {
|
||||
// Effective absorptive area.
|
||||
let absorbtionArea = (coefficients.left[i] + coefficients.right[i]) * leftRightArea +
|
||||
(coefficients.down[i] + coefficients.up[i]) * floorCeilingArea +
|
||||
(coefficients.front[i] + coefficients.back[i]) * frontBackArea;
|
||||
let meanAbsorbtionArea = absorbtionArea / totalArea;
|
||||
// Compute reverberation using Eyring equation [1].
|
||||
// [1] Beranek, Leo L. "Analysis of Sabine and Eyring equations and their
|
||||
// application to concert hall audience and chair absorption." The
|
||||
// Journal of the Acoustical Society of America, Vol. 120, No. 3.
|
||||
// (2006), pp. 1399-1399.
|
||||
durations[i] = Utils.ROOM_EYRING_CORRECTION_COEFFICIENT * k * volume /
|
||||
(-totalArea * Math.log(1 - meanAbsorbtionArea) + 4 *
|
||||
Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS[i] * volume);
|
||||
}
|
||||
return durations;
|
||||
}
|
||||
/**
|
||||
* Compute reflection coefficients from absorption coefficients.
|
||||
* @param {Object} absorptionCoefficients
|
||||
* @return {Object}
|
||||
*/
|
||||
function _computeReflectionCoefficients(absorptionCoefficients) {
|
||||
let reflectionCoefficients = [];
|
||||
for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) {
|
||||
if (Utils.DEFAULT_REFLECTION_COEFFICIENTS
|
||||
.hasOwnProperty(property)) {
|
||||
// Compute average absorption coefficient (per wall).
|
||||
reflectionCoefficients[property] = 0;
|
||||
for (let j = 0; j < Utils.NUMBER_REFLECTION_AVERAGING_BANDS; j++) {
|
||||
let bandIndex = j + Utils.ROOM_STARTING_AVERAGING_BAND;
|
||||
reflectionCoefficients[property] +=
|
||||
absorptionCoefficients[property][bandIndex];
|
||||
}
|
||||
reflectionCoefficients[property] /=
|
||||
Utils.NUMBER_REFLECTION_AVERAGING_BANDS;
|
||||
// Convert absorption coefficient to reflection coefficient.
|
||||
reflectionCoefficients[property] =
|
||||
Math.sqrt(1 - reflectionCoefficients[property]);
|
||||
}
|
||||
}
|
||||
return reflectionCoefficients;
|
||||
}
|
||||
/**
|
||||
* @class Room
|
||||
* @description Model that manages early and late reflections using acoustic
|
||||
* properties and listener position relative to a rectangular room.
|
||||
* @param {AudioContext} context
|
||||
* Associated {@link
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}.
|
||||
* @param {Object} options
|
||||
* @param {Float32Array} options.listenerPosition
|
||||
* The listener's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall.
|
||||
* Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
|
||||
* @param {Number} options.speedOfSound
|
||||
* (in meters/second). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}.
|
||||
*/
|
||||
class Room {
|
||||
constructor(context, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* EarlyReflections {@link EarlyReflections EarlyReflections} submodule.
|
||||
* @member {AudioNode} early
|
||||
* @memberof Room
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* LateReflections {@link LateReflections LateReflections} submodule.
|
||||
* @member {AudioNode} late
|
||||
* @memberof Room
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
* Ambisonic (multichannel) output {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} output
|
||||
* @memberof Room
|
||||
* @instance
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.listenerPosition == undefined) {
|
||||
options.listenerPosition = Utils.DEFAULT_POSITION.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;
|
||||
}
|
||||
// Sanitize room-properties-related arguments.
|
||||
options.dimensions = _sanitizeDimensions(options.dimensions);
|
||||
let absorptionCoefficients = _getCoefficientsFromMaterials(options.materials);
|
||||
let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients);
|
||||
let durations = _getDurationsFromProperties(options.dimensions, absorptionCoefficients, options.speedOfSound);
|
||||
// Construct submodules for early and late reflections.
|
||||
this.early = new EarlyReflections(context, {
|
||||
dimensions: options.dimensions,
|
||||
coefficients: reflectionCoefficients,
|
||||
speedOfSound: options.speedOfSound,
|
||||
listenerPosition: options.listenerPosition,
|
||||
});
|
||||
this.late = new LateReflections(context, {
|
||||
durations: durations,
|
||||
});
|
||||
this.speedOfSound = options.speedOfSound;
|
||||
// Construct auxillary audio nodes.
|
||||
this.output = context.createGain();
|
||||
this.early.output.connect(this.output);
|
||||
this._merger = context.createChannelMerger(4);
|
||||
this.late.output.connect(this._merger, 0, 0);
|
||||
this._merger.connect(this.output);
|
||||
}
|
||||
/**
|
||||
* Set the room's dimensions and wall materials.
|
||||
* @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}.
|
||||
* @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}.
|
||||
*/
|
||||
setProperties(dimensions, materials) {
|
||||
// Compute late response.
|
||||
let absorptionCoefficients = _getCoefficientsFromMaterials(materials);
|
||||
let durations = _getDurationsFromProperties(dimensions, absorptionCoefficients, this.speedOfSound);
|
||||
this.late.setDurations(durations);
|
||||
// Compute early response.
|
||||
this.early.speedOfSound = this.speedOfSound;
|
||||
let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients);
|
||||
this.early.setRoomProperties(dimensions, reflectionCoefficients);
|
||||
}
|
||||
/**
|
||||
* 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) {
|
||||
this.early.speedOfSound = this.speedOfSound;
|
||||
this.early.setListenerPosition(x, y, z);
|
||||
// Disable room effects if the listener is outside the room boundaries.
|
||||
let distance = this.getDistanceOutsideRoom(x, y, z);
|
||||
let gain = 1;
|
||||
if (distance > Utils.EPSILON_FLOAT) {
|
||||
gain = 1 - distance / Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE;
|
||||
// Clamp gain between 0 and 1.
|
||||
gain = Math.max(0, Math.min(1, gain));
|
||||
}
|
||||
this.output.gain.value = gain;
|
||||
}
|
||||
/**
|
||||
* Compute distance outside room of provided position (in meters).
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
* @return {Number}
|
||||
* Distance outside room (in meters). Returns 0 if inside room.
|
||||
*/
|
||||
getDistanceOutsideRoom(x, y, z) {
|
||||
let dx = Math.max(0, -this.early._halfDimensions.width - x, x - this.early._halfDimensions.width);
|
||||
let dy = Math.max(0, -this.early._halfDimensions.height - y, y - this.early._halfDimensions.height);
|
||||
let dz = Math.max(0, -this.early._halfDimensions.depth - z, z - this.early._halfDimensions.depth);
|
||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
}
|
||||
export default Room;
|
182
framework/resonator/vendor/resonance-es6/source.d.ts
vendored
Normal file
182
framework/resonator/vendor/resonance-es6/source.d.ts
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
export default Source;
|
||||
/**
|
||||
* ~SourceOptions
|
||||
*/
|
||||
export type Source = {
|
||||
/**
|
||||
* The source's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
*/
|
||||
position: Float32Array;
|
||||
/**
|
||||
* The source's initial forward vector. Defaults to
|
||||
* {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
*/
|
||||
forward: Float32Array;
|
||||
/**
|
||||
* The source's initial up vector. Defaults to
|
||||
* {@link Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
*/
|
||||
up: Float32Array;
|
||||
/**
|
||||
* Min. distance (in meters). Defaults to
|
||||
* {@link Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
|
||||
*/
|
||||
minDistance: number;
|
||||
/**
|
||||
* Max. distance (in meters). Defaults to
|
||||
* {@link Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
|
||||
*/
|
||||
maxDistance: number;
|
||||
/**
|
||||
* Rolloff model to use, chosen from options in
|
||||
* {@link Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to
|
||||
* {@link Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}.
|
||||
*/
|
||||
rolloff: string;
|
||||
/**
|
||||
* Input gain (linear). Defaults to
|
||||
* {@link Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
|
||||
*/
|
||||
gain: number;
|
||||
/**
|
||||
* Directivity alpha. Defaults to
|
||||
* {@link Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
|
||||
*/
|
||||
alpha: number;
|
||||
/**
|
||||
* Directivity sharpness. Defaults to
|
||||
* {@link Utils.DEFAULT_DIRECTIVITY_SHARPNESS * DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
*/
|
||||
sharpness: number;
|
||||
/**
|
||||
* Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source. Defaults to
|
||||
* {@link Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
|
||||
*/
|
||||
sourceWidth: number;
|
||||
};
|
||||
/**
|
||||
* Options for constructing a new Source.
|
||||
* @typedef {Object} Source~SourceOptions
|
||||
* @property {Float32Array} position
|
||||
* The source's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @property {Float32Array} forward
|
||||
* The source's initial forward vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
* @property {Float32Array} up
|
||||
* The source's initial up vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
* @property {Number} minDistance
|
||||
* Min. distance (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
|
||||
* @property {Number} maxDistance
|
||||
* Max. distance (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
|
||||
* @property {string} 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}.
|
||||
* @property {Number} gain Input gain (linear). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
|
||||
* @property {Number} alpha Directivity alpha. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
|
||||
* @property {Number} sharpness Directivity sharpness. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
* @property {Number} sourceWidth
|
||||
* Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
|
||||
*/
|
||||
/**
|
||||
* @class Source
|
||||
* @description Source model to spatialize an audio buffer.
|
||||
* @param {ResonanceAudio} scene Associated {@link ResonanceAudio
|
||||
* ResonanceAudio} instance.
|
||||
* @param {Source~SourceOptions} options
|
||||
* Options for constructing a new Source.
|
||||
*/
|
||||
declare class Source {
|
||||
constructor(scene: any, options: any);
|
||||
_scene: any;
|
||||
_position: any;
|
||||
_forward: any;
|
||||
_up: any;
|
||||
_dx: Float32Array;
|
||||
_right: Float32Array;
|
||||
input: any;
|
||||
_directivity: Directivity;
|
||||
_toEarly: any;
|
||||
_toLate: any;
|
||||
_attenuation: Attenuation;
|
||||
_encoder: Encoder;
|
||||
/**
|
||||
* Set source's position (in meters), where origin is the center of
|
||||
* the room.
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
*/
|
||||
setPosition(x: number, y: number, z: number): void;
|
||||
_update(): void;
|
||||
/**
|
||||
* Set source's rolloff.
|
||||
* @param {string} rolloff
|
||||
* Rolloff model to use, chosen from options in
|
||||
* {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
|
||||
*/
|
||||
setRolloff(rolloff: string): void;
|
||||
/**
|
||||
* Set source's minimum distance (in meters).
|
||||
* @param {Number} minDistance
|
||||
*/
|
||||
setMinDistance(minDistance: number): void;
|
||||
/**
|
||||
* Set source's maximum distance (in meters).
|
||||
* @param {Number} maxDistance
|
||||
*/
|
||||
setMaxDistance(maxDistance: number): void;
|
||||
/**
|
||||
* Set source's gain (linear).
|
||||
* @param {Number} gain
|
||||
*/
|
||||
setGain(gain: number): void;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void;
|
||||
/**
|
||||
* Set source's position and orientation using a
|
||||
* Three.js modelViewMatrix object.
|
||||
* @param {Float32Array} matrix4
|
||||
* The Matrix4 representing the object position and rotation in world space.
|
||||
*/
|
||||
setFromMatrix(matrix4: Float32Array): void;
|
||||
/**
|
||||
* Set the source width (in degrees). Where 0 degrees is a point source and 360
|
||||
* degrees is an omnidirectional source.
|
||||
* @param {Number} sourceWidth (in degrees).
|
||||
*/
|
||||
setSourceWidth(sourceWidth: number): void;
|
||||
/**
|
||||
* Set source's directivity pattern (defined by alpha), where 0 is an
|
||||
* omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
|
||||
* pattern. The sharpness of the pattern is increased exponentially.
|
||||
* @param {Number} alpha
|
||||
* Determines directivity pattern (0 to 1).
|
||||
* @param {Number} sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf).
|
||||
*/
|
||||
setDirectivityPattern(alpha: number, sharpness: number): void;
|
||||
}
|
||||
import Directivity from "./directivity.js";
|
||||
import Attenuation from "./attenuation.js";
|
||||
import Encoder from "./encoder.js";
|
308
framework/resonator/vendor/resonance-es6/source.js
vendored
Normal file
308
framework/resonator/vendor/resonance-es6/source.js
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* @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 Source model to spatialize an audio buffer.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
// Internal dependencies.
|
||||
import Directivity from './directivity.js';
|
||||
import Attenuation from './attenuation.js';
|
||||
import Encoder from './encoder.js';
|
||||
import Utils from './utils.js';
|
||||
/**
|
||||
* Options for constructing a new Source.
|
||||
* @typedef {Object} Source~SourceOptions
|
||||
* @property {Float32Array} position
|
||||
* The source's initial position (in meters), where origin is the center of
|
||||
* the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}.
|
||||
* @property {Float32Array} forward
|
||||
* The source's initial forward vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}.
|
||||
* @property {Float32Array} up
|
||||
* The source's initial up vector. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_UP DEFAULT_UP}.
|
||||
* @property {Number} minDistance
|
||||
* Min. distance (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}.
|
||||
* @property {Number} maxDistance
|
||||
* Max. distance (in meters). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}.
|
||||
* @property {string} 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}.
|
||||
* @property {Number} gain Input gain (linear). Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}.
|
||||
* @property {Number} alpha Directivity alpha. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}.
|
||||
* @property {Number} sharpness Directivity sharpness. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS
|
||||
* DEFAULT_DIRECTIVITY_SHARPNESS}.
|
||||
* @property {Number} sourceWidth
|
||||
* Source width (in degrees). Where 0 degrees is a point source and 360 degrees
|
||||
* is an omnidirectional source. Defaults to
|
||||
* {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}.
|
||||
*/
|
||||
/**
|
||||
* @class Source
|
||||
* @description Source model to spatialize an audio buffer.
|
||||
* @param {ResonanceAudio} scene Associated {@link ResonanceAudio
|
||||
* ResonanceAudio} instance.
|
||||
* @param {Source~SourceOptions} options
|
||||
* Options for constructing a new Source.
|
||||
*/
|
||||
class Source {
|
||||
constructor(scene, options) {
|
||||
// Public variables.
|
||||
/**
|
||||
* Mono (1-channel) input {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}.
|
||||
* @member {AudioNode} input
|
||||
* @memberof Source
|
||||
* @instance
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
// Use defaults for undefined arguments.
|
||||
if (options == undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (options.position == undefined) {
|
||||
options.position = Utils.DEFAULT_POSITION.slice();
|
||||
}
|
||||
if (options.forward == undefined) {
|
||||
options.forward = Utils.DEFAULT_FORWARD.slice();
|
||||
}
|
||||
if (options.up == undefined) {
|
||||
options.up = Utils.DEFAULT_UP.slice();
|
||||
}
|
||||
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_ROLLOFF;
|
||||
}
|
||||
if (options.gain == undefined) {
|
||||
options.gain = Utils.DEFAULT_SOURCE_GAIN;
|
||||
}
|
||||
if (options.alpha == undefined) {
|
||||
options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA;
|
||||
}
|
||||
if (options.sharpness == undefined) {
|
||||
options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS;
|
||||
}
|
||||
if (options.sourceWidth == undefined) {
|
||||
options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH;
|
||||
}
|
||||
// Member variables.
|
||||
this._scene = scene;
|
||||
this._position = options.position;
|
||||
this._forward = options.forward;
|
||||
this._up = options.up;
|
||||
this._dx = new Float32Array(3);
|
||||
this._right = Utils.crossProduct(this._forward, this._up);
|
||||
// Create audio nodes.
|
||||
let context = scene._context;
|
||||
this.input = context.createGain();
|
||||
this._directivity = new Directivity(context, {
|
||||
alpha: options.alpha,
|
||||
sharpness: options.sharpness,
|
||||
});
|
||||
this._toEarly = context.createGain();
|
||||
this._toLate = context.createGain();
|
||||
this._attenuation = new Attenuation(context, {
|
||||
minDistance: options.minDistance,
|
||||
maxDistance: options.maxDistance,
|
||||
rolloff: options.rolloff,
|
||||
});
|
||||
this._encoder = new Encoder(context, {
|
||||
ambisonicOrder: scene._ambisonicOrder,
|
||||
sourceWidth: options.sourceWidth,
|
||||
});
|
||||
// Connect nodes.
|
||||
this.input.connect(this._toLate);
|
||||
this._toLate.connect(scene._room.late.input);
|
||||
this.input.connect(this._attenuation.input);
|
||||
this._attenuation.output.connect(this._toEarly);
|
||||
this._toEarly.connect(scene._room.early.input);
|
||||
this._attenuation.output.connect(this._directivity.input);
|
||||
this._directivity.output.connect(this._encoder.input);
|
||||
this._encoder.output.connect(scene._listener.input);
|
||||
// Assign initial conditions.
|
||||
this.setPosition(options.position[0], options.position[1], options.position[2]);
|
||||
this.input.gain.value = options.gain;
|
||||
}
|
||||
/**
|
||||
* Set source's position (in meters), where origin is the center of
|
||||
* the room.
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} z
|
||||
*/
|
||||
setPosition(x, y, z) {
|
||||
// Assign new position.
|
||||
this._position[0] = x;
|
||||
this._position[1] = y;
|
||||
this._position[2] = z;
|
||||
// Handle far-field effect.
|
||||
let distance = this._scene._room.getDistanceOutsideRoom(this._position[0], this._position[1], this._position[2]);
|
||||
let gain = _computeDistanceOutsideRoom(distance);
|
||||
this._toLate.gain.value = gain;
|
||||
this._toEarly.gain.value = gain;
|
||||
this._update();
|
||||
}
|
||||
// Update the source when changing the listener's position.
|
||||
_update() {
|
||||
// Compute distance to listener.
|
||||
for (let i = 0; i < 3; i++) {
|
||||
this._dx[i] = this._position[i] - this._scene._listener.position[i];
|
||||
}
|
||||
let distance = Math.sqrt(this._dx[0] * this._dx[0] +
|
||||
this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]);
|
||||
if (distance > 0) {
|
||||
// Normalize direction vector.
|
||||
this._dx[0] /= distance;
|
||||
this._dx[1] /= distance;
|
||||
this._dx[2] /= distance;
|
||||
}
|
||||
// Compuete angle of direction vector.
|
||||
let azimuth = Math.atan2(-this._dx[0], this._dx[2]) *
|
||||
Utils.RADIANS_TO_DEGREES;
|
||||
let elevation = Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] +
|
||||
this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES;
|
||||
// Set distance/directivity/direction values.
|
||||
this._attenuation.setDistance(distance);
|
||||
this._directivity.computeAngle(this._forward, this._dx);
|
||||
this._encoder.setDirection(azimuth, elevation);
|
||||
}
|
||||
/**
|
||||
* Set source's rolloff.
|
||||
* @param {string} rolloff
|
||||
* Rolloff model to use, chosen from options in
|
||||
* {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}.
|
||||
*/
|
||||
setRolloff(rolloff) {
|
||||
this._attenuation.setRolloff(rolloff);
|
||||
}
|
||||
/**
|
||||
* Set source's minimum distance (in meters).
|
||||
* @param {Number} minDistance
|
||||
*/
|
||||
setMinDistance(minDistance) {
|
||||
this._attenuation.minDistance = minDistance;
|
||||
}
|
||||
/**
|
||||
* Set source's maximum distance (in meters).
|
||||
* @param {Number} maxDistance
|
||||
*/
|
||||
setMaxDistance(maxDistance) {
|
||||
this._attenuation.maxDistance = maxDistance;
|
||||
}
|
||||
/**
|
||||
* Set source's gain (linear).
|
||||
* @param {Number} gain
|
||||
*/
|
||||
setGain(gain) {
|
||||
this.input.gain.value = gain;
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) {
|
||||
this._forward[0] = forwardX;
|
||||
this._forward[1] = forwardY;
|
||||
this._forward[2] = forwardZ;
|
||||
this._up[0] = upX;
|
||||
this._up[1] = upY;
|
||||
this._up[2] = upZ;
|
||||
this._right = Utils.crossProduct(this._forward, this._up);
|
||||
}
|
||||
// TODO(bitllama): Make sure this works with Three.js as intended.
|
||||
/**
|
||||
* Set source's position and orientation using a
|
||||
* Three.js modelViewMatrix object.
|
||||
* @param {Float32Array} matrix4
|
||||
* The Matrix4 representing the object position and rotation in world space.
|
||||
*/
|
||||
setFromMatrix(matrix4) {
|
||||
this._right[0] = matrix4.elements[0];
|
||||
this._right[1] = matrix4.elements[1];
|
||||
this._right[2] = matrix4.elements[2];
|
||||
this._up[0] = matrix4.elements[4];
|
||||
this._up[1] = matrix4.elements[5];
|
||||
this._up[2] = matrix4.elements[6];
|
||||
this._forward[0] = matrix4.elements[8];
|
||||
this._forward[1] = matrix4.elements[9];
|
||||
this._forward[2] = matrix4.elements[10];
|
||||
// Normalize to remove scaling.
|
||||
this._right = Utils.normalizeVector(this._right);
|
||||
this._up = Utils.normalizeVector(this._up);
|
||||
this._forward = Utils.normalizeVector(this._forward);
|
||||
// Update position.
|
||||
this.setPosition(matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]);
|
||||
}
|
||||
/**
|
||||
* Set the source width (in degrees). Where 0 degrees is a point source and 360
|
||||
* degrees is an omnidirectional source.
|
||||
* @param {Number} sourceWidth (in degrees).
|
||||
*/
|
||||
setSourceWidth(sourceWidth) {
|
||||
this._encoder.setSourceWidth(sourceWidth);
|
||||
this.setPosition(this._position[0], this._position[1], this._position[2]);
|
||||
}
|
||||
/**
|
||||
* Set source's directivity pattern (defined by alpha), where 0 is an
|
||||
* omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod
|
||||
* pattern. The sharpness of the pattern is increased exponentially.
|
||||
* @param {Number} alpha
|
||||
* Determines directivity pattern (0 to 1).
|
||||
* @param {Number} sharpness
|
||||
* Determines the sharpness of the directivity pattern (1 to Inf).
|
||||
*/
|
||||
setDirectivityPattern(alpha, sharpness) {
|
||||
this._directivity.setPattern(alpha, sharpness);
|
||||
this.setPosition(this._position[0], this._position[1], this._position[2]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Determine the distance a source is outside of a room. Attenuate gain going
|
||||
* to the reflections and reverb when the source is outside of the room.
|
||||
* @param {Number} distance Distance in meters.
|
||||
* @return {Number} Gain (linear) of source.
|
||||
* @private
|
||||
*/
|
||||
function _computeDistanceOutsideRoom(distance) {
|
||||
// We apply a linear ramp from 1 to 0 as the source is up to 1m outside.
|
||||
let gain = 1;
|
||||
if (distance > Utils.EPSILON_FLOAT) {
|
||||
gain = 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE;
|
||||
// Clamp gain between 0 and 1.
|
||||
gain = Math.max(0, Math.min(1, gain));
|
||||
}
|
||||
return gain;
|
||||
}
|
||||
export default Source;
|
38
framework/resonator/vendor/resonance-es6/tables.d.ts
vendored
Normal file
38
framework/resonator/vendor/resonance-es6/tables.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
declare namespace _default {
|
||||
export { SPHERICAL_HARMONICS };
|
||||
export { SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION };
|
||||
export { SPHERICAL_HARMONICS_ELEVATION_RESOLUTION };
|
||||
export { SPHERICAL_HARMONICS_MAX_ORDER };
|
||||
export { MAX_RE_WEIGHTS };
|
||||
export { MAX_RE_WEIGHTS_RESOLUTION };
|
||||
}
|
||||
export default _default;
|
||||
/**
|
||||
* Pre-computed Spherical Harmonics Coefficients.
|
||||
*
|
||||
* This function generates an efficient lookup table of SH coefficients. It
|
||||
* exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm
|
||||
* & Plm coefficients only depend on theta, and Em only depends on phi, we
|
||||
* can separate the equation along these lines. Em does not depend on
|
||||
* degree, so we only need to compute (2 * l) per azimuth Em total and
|
||||
* Nlm * Plm is symmetrical across indexes, so only positive indexes are
|
||||
* computed ((l + 1) * (l + 2) / 2 - 1) per elevation.
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
declare const SPHERICAL_HARMONICS: Float32Array;
|
||||
/** @type {Number} */
|
||||
declare const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION: number;
|
||||
/** @type {Number} */
|
||||
declare const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION: number;
|
||||
/**
|
||||
* The maximum allowed ambisonic order.
|
||||
* @type {Number}
|
||||
*/
|
||||
declare const SPHERICAL_HARMONICS_MAX_ORDER: number;
|
||||
/**
|
||||
* Pre-computed per-band weighting coefficients for producing energy-preserving
|
||||
* Max-Re sources.
|
||||
*/
|
||||
declare const MAX_RE_WEIGHTS: number[][];
|
||||
/** @type {Number} */
|
||||
declare const MAX_RE_WEIGHTS_RESOLUTION: number;
|
1144
framework/resonator/vendor/resonance-es6/tables.js
vendored
Normal file
1144
framework/resonator/vendor/resonance-es6/tables.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
98
framework/resonator/vendor/resonance-es6/utils.d.ts
vendored
Normal file
98
framework/resonator/vendor/resonance-es6/utils.d.ts
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
export default Utils;
|
||||
/**
|
||||
* @class Utils
|
||||
* @description A set of defaults, constants and utility functions.
|
||||
*/
|
||||
declare class Utils {
|
||||
/**
|
||||
* Properties describing the geometry of a room.
|
||||
* @typedef {Object} Utils~RoomDimensions
|
||||
* @property {Number} width (in meters).
|
||||
* @property {Number} height (in meters).
|
||||
* @property {Number} depth (in meters).
|
||||
*/
|
||||
/**
|
||||
* Properties describing the wall materials (from
|
||||
* {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS})
|
||||
* of a room.
|
||||
* @typedef {Object} Utils~RoomMaterials
|
||||
* @property {String} left Left-wall material name.
|
||||
* @property {String} right Right-wall material name.
|
||||
* @property {String} front Front-wall material name.
|
||||
* @property {String} back Back-wall material name.
|
||||
* @property {String} up Up-wall material name.
|
||||
* @property {String} down Down-wall material name.
|
||||
*/
|
||||
/**
|
||||
* ResonanceAudio library logging function.
|
||||
* @type {Function}
|
||||
* @param {any} Message to be printed out.
|
||||
* @private
|
||||
*/
|
||||
private static log;
|
||||
}
|
||||
declare namespace Utils {
|
||||
const DEFAULT_SOURCE_GAIN: number;
|
||||
const LISTENER_MAX_OUTSIDE_ROOM_DISTANCE: number;
|
||||
const SOURCE_MAX_OUTSIDE_ROOM_DISTANCE: number;
|
||||
const DEFAULT_SOURCE_DISTANCE: number;
|
||||
const DEFAULT_POSITION: Float32Array;
|
||||
const DEFAULT_FORWARD: Float32Array;
|
||||
const DEFAULT_UP: Float32Array;
|
||||
const DEFAULT_RIGHT: Float32Array;
|
||||
const DEFAULT_SPEED_OF_SOUND: number;
|
||||
const ATTENUATION_ROLLOFFS: any[];
|
||||
const DEFAULT_ATTENUATION_ROLLOFF: string;
|
||||
const DEFAULT_MIN_DISTANCE: number;
|
||||
const DEFAULT_MAX_DISTANCE: number;
|
||||
const DEFAULT_DIRECTIVITY_ALPHA: number;
|
||||
const DEFAULT_DIRECTIVITY_SHARPNESS: number;
|
||||
const DEFAULT_AZIMUTH: number;
|
||||
const DEFAULT_ELEVATION: number;
|
||||
const DEFAULT_AMBISONIC_ORDER: number;
|
||||
const DEFAULT_SOURCE_WIDTH: number;
|
||||
const DEFAULT_REFLECTION_MAX_DURATION: number;
|
||||
const DEFAULT_REFLECTION_CUTOFF_FREQUENCY: number;
|
||||
const DEFAULT_REFLECTION_COEFFICIENTS: any;
|
||||
const DEFAULT_REFLECTION_MIN_DISTANCE: number;
|
||||
const DEFAULT_ROOM_DIMENSIONS: any;
|
||||
const DEFAULT_REFLECTION_MULTIPLIER: number;
|
||||
const DEFAULT_REVERB_BANDWIDTH: number;
|
||||
const DEFAULT_REVERB_DURATION_MULTIPLIER: number;
|
||||
const DEFAULT_REVERB_PREDELAY: number;
|
||||
const DEFAULT_REVERB_TAIL_ONSET: number;
|
||||
const DEFAULT_REVERB_GAIN: number;
|
||||
const DEFAULT_REVERB_MAX_DURATION: number;
|
||||
const DEFAULT_REVERB_FREQUENCY_BANDS: any[];
|
||||
const NUMBER_REVERB_FREQUENCY_BANDS: number;
|
||||
const DEFAULT_REVERB_DURATIONS: Float32Array;
|
||||
const ROOM_MATERIAL_COEFFICIENTS: any;
|
||||
const DEFAULT_ROOM_MATERIALS: any;
|
||||
const NUMBER_REFLECTION_AVERAGING_BANDS: number;
|
||||
const ROOM_STARTING_AVERAGING_BAND: number;
|
||||
const ROOM_MIN_VOLUME: number;
|
||||
const ROOM_AIR_ABSORPTION_COEFFICIENTS: Float32Array;
|
||||
const ROOM_EYRING_CORRECTION_COEFFICIENT: number;
|
||||
const TWO_PI: number;
|
||||
const TWENTY_FOUR_LOG10: number;
|
||||
const LOG1000: number;
|
||||
const LOG2_DIV2: number;
|
||||
const DEGREES_TO_RADIANS: number;
|
||||
const RADIANS_TO_DEGREES: number;
|
||||
const EPSILON_FLOAT: number;
|
||||
/**
|
||||
* Normalize a 3-d vector.
|
||||
* @param {Float32Array} v 3-element vector.
|
||||
* @return {Float32Array} 3-element vector.
|
||||
* @private
|
||||
*/
|
||||
function normalizeVector(v: Float32Array): Float32Array;
|
||||
/**
|
||||
* Cross-product between two 3-d vectors.
|
||||
* @param {Float32Array} a 3-element vector.
|
||||
* @param {Float32Array} b 3-element vector.
|
||||
* @return {Float32Array}
|
||||
* @private
|
||||
*/
|
||||
function crossProduct(a: Float32Array, b: Float32Array): Float32Array;
|
||||
}
|
379
framework/resonator/vendor/resonance-es6/utils.js
vendored
Normal file
379
framework/resonator/vendor/resonance-es6/utils.js
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* @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 common utilities, mathematical constants,
|
||||
* and default values.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
/**
|
||||
* @class Utils
|
||||
* @description A set of defaults, constants and utility functions.
|
||||
*/
|
||||
class Utils {
|
||||
/**
|
||||
* Properties describing the geometry of a room.
|
||||
* @typedef {Object} Utils~RoomDimensions
|
||||
* @property {Number} width (in meters).
|
||||
* @property {Number} height (in meters).
|
||||
* @property {Number} depth (in meters).
|
||||
*/
|
||||
/**
|
||||
* Properties describing the wall materials (from
|
||||
* {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS})
|
||||
* of a room.
|
||||
* @typedef {Object} Utils~RoomMaterials
|
||||
* @property {String} left Left-wall material name.
|
||||
* @property {String} right Right-wall material name.
|
||||
* @property {String} front Front-wall material name.
|
||||
* @property {String} back Back-wall material name.
|
||||
* @property {String} up Up-wall material name.
|
||||
* @property {String} down Down-wall material name.
|
||||
*/
|
||||
/**
|
||||
* ResonanceAudio library logging function.
|
||||
* @type {Function}
|
||||
* @param {any} Message to be printed out.
|
||||
* @private
|
||||
*/
|
||||
static log() {
|
||||
window.console.log.apply(window.console, [
|
||||
'%c[ResonanceAudio]%c '
|
||||
+ Array.prototype.slice.call(arguments).join(' ') + ' %c(@'
|
||||
+ performance.now().toFixed(2) + 'ms)',
|
||||
'background: #BBDEFB; color: #FF5722; font-weight: 700',
|
||||
'font-weight: 400',
|
||||
'color: #AAA',
|
||||
]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Default input gain (linear).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_SOURCE_GAIN = 1;
|
||||
/**
|
||||
* Maximum outside-the-room distance to attenuate far-field listener by.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE = 1;
|
||||
/**
|
||||
* Maximum outside-the-room distance to attenuate far-field sources by.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE = 1;
|
||||
/**
|
||||
* Default distance from listener when setting angle.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_SOURCE_DISTANCE = 1;
|
||||
/** @type {Float32Array} */
|
||||
Utils.DEFAULT_POSITION = [0, 0, 0];
|
||||
/** @type {Float32Array} */
|
||||
Utils.DEFAULT_FORWARD = [0, 0, -1];
|
||||
/** @type {Float32Array} */
|
||||
Utils.DEFAULT_UP = [0, 1, 0];
|
||||
/** @type {Float32Array} */
|
||||
Utils.DEFAULT_RIGHT = [1, 0, 0];
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_SPEED_OF_SOUND = 343;
|
||||
/** Rolloff models (e.g. 'logarithmic', 'linear', or 'none').
|
||||
* @type {Array}
|
||||
*/
|
||||
Utils.ATTENUATION_ROLLOFFS = ['logarithmic', 'linear', 'none'];
|
||||
/** Default rolloff model ('logarithmic').
|
||||
* @type {string}
|
||||
*/
|
||||
Utils.DEFAULT_ATTENUATION_ROLLOFF = 'logarithmic';
|
||||
/** @type {Number} */
|
||||
Utils.DEFAULT_MIN_DISTANCE = 1;
|
||||
/** @type {Number} */
|
||||
Utils.DEFAULT_MAX_DISTANCE = 1000;
|
||||
/**
|
||||
* The default alpha (i.e. microphone pattern).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_DIRECTIVITY_ALPHA = 0;
|
||||
/**
|
||||
* The default pattern sharpness (i.e. pattern exponent).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_DIRECTIVITY_SHARPNESS = 1;
|
||||
/**
|
||||
* Default azimuth (in degrees). Suitable range is 0 to 360.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_AZIMUTH = 0;
|
||||
/**
|
||||
* Default elevation (in degres).
|
||||
* Suitable range is from -90 (below) to 90 (above).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_ELEVATION = 0;
|
||||
/**
|
||||
* The default ambisonic order.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_AMBISONIC_ORDER = 1;
|
||||
/**
|
||||
* The default source width.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_SOURCE_WIDTH = 0;
|
||||
/**
|
||||
* The maximum delay (in seconds) of a single wall reflection.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REFLECTION_MAX_DURATION = 0.5;
|
||||
/**
|
||||
* The -12dB cutoff frequency (in Hertz) for the lowpass filter applied to
|
||||
* all reflections.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY = 6400; // Uses -12dB cutoff.
|
||||
/**
|
||||
* The default reflection coefficients (where 0 = no reflection, 1 = perfect
|
||||
* reflection, -1 = mirrored reflection (180-degrees out of phase)).
|
||||
* @type {Object}
|
||||
*/
|
||||
Utils.DEFAULT_REFLECTION_COEFFICIENTS = {
|
||||
left: 0, right: 0, front: 0, back: 0, down: 0, up: 0,
|
||||
};
|
||||
/**
|
||||
* The minimum distance we consider the listener to be to any given wall.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REFLECTION_MIN_DISTANCE = 1;
|
||||
/**
|
||||
* Default room dimensions (in meters).
|
||||
* @type {Object}
|
||||
*/
|
||||
Utils.DEFAULT_ROOM_DIMENSIONS = {
|
||||
width: 0, height: 0, depth: 0,
|
||||
};
|
||||
/**
|
||||
* The multiplier to apply to distances from the listener to each wall.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REFLECTION_MULTIPLIER = 1;
|
||||
/** The default bandwidth (in octaves) of the center frequencies.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_BANDWIDTH = 1;
|
||||
/** The default multiplier applied when computing tail lengths.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_DURATION_MULTIPLIER = 1;
|
||||
/**
|
||||
* The late reflections pre-delay (in milliseconds).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_PREDELAY = 1.5;
|
||||
/**
|
||||
* The length of the beginning of the impulse response to apply a
|
||||
* half-Hann window to.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_TAIL_ONSET = 3.8;
|
||||
/**
|
||||
* The default gain (linear).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_GAIN = 0.01;
|
||||
/**
|
||||
* The maximum impulse response length (in seconds).
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_MAX_DURATION = 3;
|
||||
/**
|
||||
* Center frequencies of the multiband late reflections.
|
||||
* Nine bands are computed by: 31.25 * 2^(0:8).
|
||||
* @type {Array}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_FREQUENCY_BANDS = [
|
||||
31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000,
|
||||
];
|
||||
/**
|
||||
* The number of frequency bands.
|
||||
*/
|
||||
Utils.NUMBER_REVERB_FREQUENCY_BANDS =
|
||||
Utils.DEFAULT_REVERB_FREQUENCY_BANDS.length;
|
||||
/**
|
||||
* The default multiband RT60 durations (in seconds).
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
Utils.DEFAULT_REVERB_DURATIONS =
|
||||
new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS);
|
||||
/**
|
||||
* Pre-defined frequency-dependent absorption coefficients for listed materials.
|
||||
* Currently supported materials are:
|
||||
* <ul>
|
||||
* <li>'transparent'</li>
|
||||
* <li>'acoustic-ceiling-tiles'</li>
|
||||
* <li>'brick-bare'</li>
|
||||
* <li>'brick-painted'</li>
|
||||
* <li>'concrete-block-coarse'</li>
|
||||
* <li>'concrete-block-painted'</li>
|
||||
* <li>'curtain-heavy'</li>
|
||||
* <li>'fiber-glass-insulation'</li>
|
||||
* <li>'glass-thin'</li>
|
||||
* <li>'glass-thick'</li>
|
||||
* <li>'grass'</li>
|
||||
* <li>'linoleum-on-concrete'</li>
|
||||
* <li>'marble'</li>
|
||||
* <li>'metal'</li>
|
||||
* <li>'parquet-on-concrete'</li>
|
||||
* <li>'plaster-smooth'</li>
|
||||
* <li>'plywood-panel'</li>
|
||||
* <li>'polished-concrete-or-tile'</li>
|
||||
* <li>'sheetrock'</li>
|
||||
* <li>'water-or-ice-surface'</li>
|
||||
* <li>'wood-ceiling'</li>
|
||||
* <li>'wood-panel'</li>
|
||||
* <li>'uniform'</li>
|
||||
* </ul>
|
||||
* @type {Object}
|
||||
*/
|
||||
Utils.ROOM_MATERIAL_COEFFICIENTS = {
|
||||
'transparent': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000],
|
||||
'acoustic-ceiling-tiles': [0.672, 0.675, 0.700, 0.660, 0.720, 0.920, 0.880, 0.750, 1.000],
|
||||
'brick-bare': [0.030, 0.030, 0.030, 0.030, 0.030, 0.040, 0.050, 0.070, 0.140],
|
||||
'brick-painted': [0.006, 0.007, 0.010, 0.010, 0.020, 0.020, 0.020, 0.030, 0.060],
|
||||
'concrete-block-coarse': [0.360, 0.360, 0.360, 0.440, 0.310, 0.290, 0.390, 0.250, 0.500],
|
||||
'concrete-block-painted': [0.092, 0.090, 0.100, 0.050, 0.060, 0.070, 0.090, 0.080, 0.160],
|
||||
'curtain-heavy': [0.073, 0.106, 0.140, 0.350, 0.550, 0.720, 0.700, 0.650, 1.000],
|
||||
'fiber-glass-insulation': [0.193, 0.220, 0.220, 0.820, 0.990, 0.990, 0.990, 0.990, 1.000],
|
||||
'glass-thin': [0.180, 0.169, 0.180, 0.060, 0.040, 0.030, 0.020, 0.020, 0.040],
|
||||
'glass-thick': [0.350, 0.350, 0.350, 0.250, 0.180, 0.120, 0.070, 0.040, 0.080],
|
||||
'grass': [0.050, 0.050, 0.150, 0.250, 0.400, 0.550, 0.600, 0.600, 0.600],
|
||||
'linoleum-on-concrete': [0.020, 0.020, 0.020, 0.030, 0.030, 0.030, 0.030, 0.020, 0.040],
|
||||
'marble': [0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.020, 0.020, 0.040],
|
||||
'metal': [0.030, 0.035, 0.040, 0.040, 0.050, 0.050, 0.050, 0.070, 0.090],
|
||||
'parquet-on-concrete': [0.028, 0.030, 0.040, 0.040, 0.070, 0.060, 0.060, 0.070, 0.140],
|
||||
'plaster-rough': [0.017, 0.018, 0.020, 0.030, 0.040, 0.050, 0.040, 0.030, 0.060],
|
||||
'plaster-smooth': [0.011, 0.012, 0.013, 0.015, 0.020, 0.030, 0.040, 0.050, 0.100],
|
||||
'plywood-panel': [0.400, 0.340, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220],
|
||||
'polished-concrete-or-tile': [0.008, 0.008, 0.010, 0.010, 0.015, 0.020, 0.020, 0.020, 0.040],
|
||||
'sheet-rock': [0.290, 0.279, 0.290, 0.100, 0.050, 0.040, 0.070, 0.090, 0.180],
|
||||
'water-or-ice-surface': [0.006, 0.006, 0.008, 0.008, 0.013, 0.015, 0.020, 0.025, 0.050],
|
||||
'wood-ceiling': [0.150, 0.147, 0.150, 0.110, 0.100, 0.070, 0.060, 0.070, 0.140],
|
||||
'wood-panel': [0.280, 0.280, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220],
|
||||
'uniform': [0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500],
|
||||
};
|
||||
/**
|
||||
* Default materials that use strings from
|
||||
* {@linkcode Utils.MATERIAL_COEFFICIENTS MATERIAL_COEFFICIENTS}
|
||||
* @type {Object}
|
||||
*/
|
||||
Utils.DEFAULT_ROOM_MATERIALS = {
|
||||
left: 'transparent', right: 'transparent', front: 'transparent',
|
||||
back: 'transparent', down: 'transparent', up: 'transparent',
|
||||
};
|
||||
/**
|
||||
* The number of bands to average over when computing reflection coefficients.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.NUMBER_REFLECTION_AVERAGING_BANDS = 3;
|
||||
/**
|
||||
* The starting band to average over when computing reflection coefficients.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.ROOM_STARTING_AVERAGING_BAND = 4;
|
||||
/**
|
||||
* The minimum threshold for room volume.
|
||||
* Room model is disabled if volume is below this value.
|
||||
* @type {Number} */
|
||||
Utils.ROOM_MIN_VOLUME = 1e-4;
|
||||
/**
|
||||
* Air absorption coefficients per frequency band.
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS =
|
||||
[0.0006, 0.0006, 0.0007, 0.0008, 0.0010, 0.0015, 0.0026, 0.0060, 0.0207];
|
||||
/**
|
||||
* A scalar correction value to ensure Sabine and Eyring produce the same RT60
|
||||
* value at the cross-over threshold.
|
||||
* @type {Number}
|
||||
*/
|
||||
Utils.ROOM_EYRING_CORRECTION_COEFFICIENT = 1.38;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.TWO_PI = 6.28318530717959;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.TWENTY_FOUR_LOG10 = 55.2620422318571;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.LOG1000 = 6.90775527898214;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.LOG2_DIV2 = 0.346573590279973;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.DEGREES_TO_RADIANS = 0.017453292519943;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.RADIANS_TO_DEGREES = 57.295779513082323;
|
||||
/**
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
Utils.EPSILON_FLOAT = 1e-8;
|
||||
/**
|
||||
* Normalize a 3-d vector.
|
||||
* @param {Float32Array} v 3-element vector.
|
||||
* @return {Float32Array} 3-element vector.
|
||||
* @private
|
||||
*/
|
||||
Utils.normalizeVector = v => {
|
||||
let n = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
if (n > Utils.EPSILON_FLOAT) {
|
||||
n = 1 / n;
|
||||
v[0] *= n;
|
||||
v[1] *= n;
|
||||
v[2] *= n;
|
||||
}
|
||||
return v;
|
||||
};
|
||||
/**
|
||||
* Cross-product between two 3-d vectors.
|
||||
* @param {Float32Array} a 3-element vector.
|
||||
* @param {Float32Array} b 3-element vector.
|
||||
* @return {Float32Array}
|
||||
* @private
|
||||
*/
|
||||
Utils.crossProduct = (a, b) => {
|
||||
return [
|
||||
a[1] * b[2] - a[2] * b[1],
|
||||
a[2] * b[0] - a[0] * b[2],
|
||||
a[0] * b[1] - a[1] * b[0],
|
||||
];
|
||||
};
|
||||
export default Utils;
|
2
framework/resonator/vendor/resonance-es6/version.d.ts
vendored
Normal file
2
framework/resonator/vendor/resonance-es6/version.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare var _default: "1.0.0";
|
||||
export default _default;
|
24
framework/resonator/vendor/resonance-es6/version.js
vendored
Normal file
24
framework/resonator/vendor/resonance-es6/version.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 version.
|
||||
* @author Andrew Allen <bitllama@google.com>
|
||||
*/
|
||||
'use strict';
|
||||
/**
|
||||
* ResonanceAudio library version
|
||||
* @type {String}
|
||||
*/
|
||||
export default '1.0.0';
|
1
framework/resonator/vendor/tsm/constants.d.ts
vendored
Normal file
1
framework/resonator/vendor/tsm/constants.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const epsilon = 0.00001;
|
1
framework/resonator/vendor/tsm/constants.js
vendored
Normal file
1
framework/resonator/vendor/tsm/constants.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export const epsilon = 0.00001;
|
23
framework/resonator/vendor/tsm/mat2.d.ts
vendored
Normal file
23
framework/resonator/vendor/tsm/mat2.d.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import vec2 from './vec2';
|
||||
export default class mat2 {
|
||||
constructor(values?: number[]);
|
||||
private values;
|
||||
static readonly identity: mat2;
|
||||
at(index: number): number;
|
||||
init(values: number[]): mat2;
|
||||
reset(): void;
|
||||
copy(dest?: mat2): mat2;
|
||||
all(): number[];
|
||||
row(index: number): number[];
|
||||
col(index: number): number[];
|
||||
equals(matrix: mat2, threshold?: number): boolean;
|
||||
determinant(): number;
|
||||
setIdentity(): mat2;
|
||||
transpose(): mat2;
|
||||
inverse(): mat2;
|
||||
multiply(matrix: mat2): mat2;
|
||||
rotate(angle: number): mat2;
|
||||
multiplyVec2(vector: vec2, result: vec2): vec2;
|
||||
scale(vector: vec2): mat2;
|
||||
static product(m1: mat2, m2: mat2, result: mat2): mat2;
|
||||
}
|
161
framework/resonator/vendor/tsm/mat2.js
vendored
Normal file
161
framework/resonator/vendor/tsm/mat2.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
import vec2 from './vec2';
|
||||
import { epsilon } from './constants';
|
||||
export default class mat2 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(4);
|
||||
if (values !== undefined) {
|
||||
this.init(values);
|
||||
}
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
init(values) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
reset() {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
this.values[i] = 0;
|
||||
}
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new mat2();
|
||||
}
|
||||
for (let i = 0; i < 4; i++) {
|
||||
dest.values[i] = this.values[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
all() {
|
||||
const data = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
data[i] = this.values[i];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
row(index) {
|
||||
return [this.values[index * 2 + 0], this.values[index * 2 + 1]];
|
||||
}
|
||||
col(index) {
|
||||
return [this.values[index], this.values[index + 2]];
|
||||
}
|
||||
equals(matrix, threshold = epsilon) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (Math.abs(this.values[i] - matrix.at(i)) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
determinant() {
|
||||
return this.values[0] * this.values[3] - this.values[2] * this.values[1];
|
||||
}
|
||||
setIdentity() {
|
||||
this.values[0] = 1;
|
||||
this.values[1] = 0;
|
||||
this.values[2] = 0;
|
||||
this.values[3] = 1;
|
||||
return this;
|
||||
}
|
||||
transpose() {
|
||||
const temp = this.values[1];
|
||||
this.values[1] = this.values[2];
|
||||
this.values[2] = temp;
|
||||
return this;
|
||||
}
|
||||
inverse() {
|
||||
let det = this.determinant();
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
const a11 = this.values[0];
|
||||
this.values[0] = det * this.values[3];
|
||||
this.values[1] = det * -this.values[1];
|
||||
this.values[2] = det * -this.values[2];
|
||||
this.values[3] = det * a11;
|
||||
return this;
|
||||
}
|
||||
multiply(matrix) {
|
||||
const a11 = this.values[0];
|
||||
const a12 = this.values[1];
|
||||
const a21 = this.values[2];
|
||||
const a22 = this.values[3];
|
||||
this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2);
|
||||
this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3);
|
||||
this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2);
|
||||
this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3);
|
||||
return this;
|
||||
}
|
||||
rotate(angle) {
|
||||
const a11 = this.values[0];
|
||||
const a12 = this.values[1];
|
||||
const a21 = this.values[2];
|
||||
const a22 = this.values[3];
|
||||
const sin = Math.sin(angle);
|
||||
const cos = Math.cos(angle);
|
||||
this.values[0] = a11 * cos + a12 * sin;
|
||||
this.values[1] = a11 * -sin + a12 * cos;
|
||||
this.values[2] = a21 * cos + a22 * sin;
|
||||
this.values[3] = a21 * -sin + a22 * cos;
|
||||
return this;
|
||||
}
|
||||
multiplyVec2(vector, result) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
if (result) {
|
||||
result.xy = [
|
||||
x * this.values[0] + y * this.values[1],
|
||||
x * this.values[2] + y * this.values[3]
|
||||
];
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new vec2([
|
||||
x * this.values[0] + y * this.values[1],
|
||||
x * this.values[2] + y * this.values[3]
|
||||
]);
|
||||
}
|
||||
}
|
||||
scale(vector) {
|
||||
const a11 = this.values[0];
|
||||
const a12 = this.values[1];
|
||||
const a21 = this.values[2];
|
||||
const a22 = this.values[3];
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
this.values[0] = a11 * x;
|
||||
this.values[1] = a12 * y;
|
||||
this.values[2] = a21 * x;
|
||||
this.values[3] = a22 * y;
|
||||
return this;
|
||||
}
|
||||
static product(m1, m2, result) {
|
||||
const a11 = m1.at(0);
|
||||
const a12 = m1.at(1);
|
||||
const a21 = m1.at(2);
|
||||
const a22 = m1.at(3);
|
||||
if (result) {
|
||||
result.init([
|
||||
a11 * m2.at(0) + a12 * m2.at(2),
|
||||
a11 * m2.at(1) + a12 * m2.at(3),
|
||||
a21 * m2.at(0) + a22 * m2.at(2),
|
||||
a21 * m2.at(1) + a22 * m2.at(3)
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new mat2([
|
||||
a11 * m2.at(0) + a12 * m2.at(2),
|
||||
a11 * m2.at(1) + a12 * m2.at(3),
|
||||
a21 * m2.at(0) + a22 * m2.at(2),
|
||||
a21 * m2.at(1) + a22 * m2.at(3)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mat2.identity = new mat2().setIdentity();
|
28
framework/resonator/vendor/tsm/mat3.d.ts
vendored
Normal file
28
framework/resonator/vendor/tsm/mat3.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import mat4 from './mat4';
|
||||
import quat from './quat';
|
||||
import vec2 from './vec2';
|
||||
import vec3 from './vec3';
|
||||
export default class mat3 {
|
||||
constructor(values?: number[]);
|
||||
private values;
|
||||
static readonly identity: mat3;
|
||||
at(index: number): number;
|
||||
init(values: number[]): mat3;
|
||||
reset(): void;
|
||||
copy(dest?: mat3): mat3;
|
||||
all(): number[];
|
||||
row(index: number): number[];
|
||||
col(index: number): number[];
|
||||
equals(matrix: mat3, threshold?: number): boolean;
|
||||
determinant(): number;
|
||||
setIdentity(): mat3;
|
||||
transpose(): mat3;
|
||||
inverse(): mat3;
|
||||
multiply(matrix: mat3): mat3;
|
||||
multiplyVec2(vector: vec2, result: vec2): vec2;
|
||||
multiplyVec3(vector: vec3, result: vec3): vec3;
|
||||
toMat4(result: mat4): mat4;
|
||||
toQuat(): quat;
|
||||
rotate(angle: number, axis: vec3): mat3;
|
||||
static product(m1: mat3, m2: mat3, result: mat3): mat3;
|
||||
}
|
392
framework/resonator/vendor/tsm/mat3.js
vendored
Normal file
392
framework/resonator/vendor/tsm/mat3.js
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
import mat4 from './mat4';
|
||||
import quat from './quat';
|
||||
import vec2 from './vec2';
|
||||
import vec3 from './vec3';
|
||||
import { epsilon } from './constants';
|
||||
export default class mat3 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(9);
|
||||
if (values !== undefined) {
|
||||
this.init(values);
|
||||
}
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
init(values) {
|
||||
for (let i = 0; i < 9; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
reset() {
|
||||
for (let i = 0; i < 9; i++) {
|
||||
this.values[i] = 0;
|
||||
}
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new mat3();
|
||||
}
|
||||
for (let i = 0; i < 9; i++) {
|
||||
dest.values[i] = this.values[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
all() {
|
||||
const data = [];
|
||||
for (let i = 0; i < 9; i++) {
|
||||
data[i] = this.values[i];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
row(index) {
|
||||
return [
|
||||
this.values[index * 3 + 0],
|
||||
this.values[index * 3 + 1],
|
||||
this.values[index * 3 + 2]
|
||||
];
|
||||
}
|
||||
col(index) {
|
||||
return [this.values[index], this.values[index + 3], this.values[index + 6]];
|
||||
}
|
||||
equals(matrix, threshold = epsilon) {
|
||||
for (let i = 0; i < 9; i++) {
|
||||
if (Math.abs(this.values[i] - matrix.at(i)) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
determinant() {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a10 = this.values[3];
|
||||
const a11 = this.values[4];
|
||||
const a12 = this.values[5];
|
||||
const a20 = this.values[6];
|
||||
const a21 = this.values[7];
|
||||
const a22 = this.values[8];
|
||||
const det01 = a22 * a11 - a12 * a21;
|
||||
const det11 = -a22 * a10 + a12 * a20;
|
||||
const det21 = a21 * a10 - a11 * a20;
|
||||
return a00 * det01 + a01 * det11 + a02 * det21;
|
||||
}
|
||||
setIdentity() {
|
||||
this.values[0] = 1;
|
||||
this.values[1] = 0;
|
||||
this.values[2] = 0;
|
||||
this.values[3] = 0;
|
||||
this.values[4] = 1;
|
||||
this.values[5] = 0;
|
||||
this.values[6] = 0;
|
||||
this.values[7] = 0;
|
||||
this.values[8] = 1;
|
||||
return this;
|
||||
}
|
||||
transpose() {
|
||||
const temp01 = this.values[1];
|
||||
const temp02 = this.values[2];
|
||||
const temp12 = this.values[5];
|
||||
this.values[1] = this.values[3];
|
||||
this.values[2] = this.values[6];
|
||||
this.values[3] = temp01;
|
||||
this.values[5] = this.values[7];
|
||||
this.values[6] = temp02;
|
||||
this.values[7] = temp12;
|
||||
return this;
|
||||
}
|
||||
inverse() {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a10 = this.values[3];
|
||||
const a11 = this.values[4];
|
||||
const a12 = this.values[5];
|
||||
const a20 = this.values[6];
|
||||
const a21 = this.values[7];
|
||||
const a22 = this.values[8];
|
||||
const det01 = a22 * a11 - a12 * a21;
|
||||
const det11 = -a22 * a10 + a12 * a20;
|
||||
const det21 = a21 * a10 - a11 * a20;
|
||||
let det = a00 * det01 + a01 * det11 + a02 * det21;
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
this.values[0] = det01 * det;
|
||||
this.values[1] = (-a22 * a01 + a02 * a21) * det;
|
||||
this.values[2] = (a12 * a01 - a02 * a11) * det;
|
||||
this.values[3] = det11 * det;
|
||||
this.values[4] = (a22 * a00 - a02 * a20) * det;
|
||||
this.values[5] = (-a12 * a00 + a02 * a10) * det;
|
||||
this.values[6] = det21 * det;
|
||||
this.values[7] = (-a21 * a00 + a01 * a20) * det;
|
||||
this.values[8] = (a11 * a00 - a01 * a10) * det;
|
||||
return this;
|
||||
}
|
||||
multiply(matrix) {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a10 = this.values[3];
|
||||
const a11 = this.values[4];
|
||||
const a12 = this.values[5];
|
||||
const a20 = this.values[6];
|
||||
const a21 = this.values[7];
|
||||
const a22 = this.values[8];
|
||||
const b00 = matrix.at(0);
|
||||
const b01 = matrix.at(1);
|
||||
const b02 = matrix.at(2);
|
||||
const b10 = matrix.at(3);
|
||||
const b11 = matrix.at(4);
|
||||
const b12 = matrix.at(5);
|
||||
const b20 = matrix.at(6);
|
||||
const b21 = matrix.at(7);
|
||||
const b22 = matrix.at(8);
|
||||
this.values[0] = b00 * a00 + b01 * a10 + b02 * a20;
|
||||
this.values[1] = b00 * a01 + b01 * a11 + b02 * a21;
|
||||
this.values[2] = b00 * a02 + b01 * a12 + b02 * a22;
|
||||
this.values[3] = b10 * a00 + b11 * a10 + b12 * a20;
|
||||
this.values[4] = b10 * a01 + b11 * a11 + b12 * a21;
|
||||
this.values[5] = b10 * a02 + b11 * a12 + b12 * a22;
|
||||
this.values[6] = b20 * a00 + b21 * a10 + b22 * a20;
|
||||
this.values[7] = b20 * a01 + b21 * a11 + b22 * a21;
|
||||
this.values[8] = b20 * a02 + b21 * a12 + b22 * a22;
|
||||
return this;
|
||||
}
|
||||
multiplyVec2(vector, result) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
if (result) {
|
||||
result.xy = [
|
||||
x * this.values[0] + y * this.values[3] + this.values[6],
|
||||
x * this.values[1] + y * this.values[4] + this.values[7]
|
||||
];
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new vec2([
|
||||
x * this.values[0] + y * this.values[3] + this.values[6],
|
||||
x * this.values[1] + y * this.values[4] + this.values[7]
|
||||
]);
|
||||
}
|
||||
}
|
||||
multiplyVec3(vector, result) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
if (result) {
|
||||
result.xyz = [
|
||||
x * this.values[0] + y * this.values[3] + z * this.values[6],
|
||||
x * this.values[1] + y * this.values[4] + z * this.values[7],
|
||||
x * this.values[2] + y * this.values[5] + z * this.values[8]
|
||||
];
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new vec3([
|
||||
x * this.values[0] + y * this.values[3] + z * this.values[6],
|
||||
x * this.values[1] + y * this.values[4] + z * this.values[7],
|
||||
x * this.values[2] + y * this.values[5] + z * this.values[8]
|
||||
]);
|
||||
}
|
||||
}
|
||||
toMat4(result) {
|
||||
if (result) {
|
||||
result.init([
|
||||
this.values[0],
|
||||
this.values[1],
|
||||
this.values[2],
|
||||
0,
|
||||
this.values[3],
|
||||
this.values[4],
|
||||
this.values[5],
|
||||
0,
|
||||
this.values[6],
|
||||
this.values[7],
|
||||
this.values[8],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new mat4([
|
||||
this.values[0],
|
||||
this.values[1],
|
||||
this.values[2],
|
||||
0,
|
||||
this.values[3],
|
||||
this.values[4],
|
||||
this.values[5],
|
||||
0,
|
||||
this.values[6],
|
||||
this.values[7],
|
||||
this.values[8],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
]);
|
||||
}
|
||||
}
|
||||
toQuat() {
|
||||
const m00 = this.values[0];
|
||||
const m01 = this.values[1];
|
||||
const m02 = this.values[2];
|
||||
const m10 = this.values[3];
|
||||
const m11 = this.values[4];
|
||||
const m12 = this.values[5];
|
||||
const m20 = this.values[6];
|
||||
const m21 = this.values[7];
|
||||
const m22 = this.values[8];
|
||||
const fourXSquaredMinus1 = m00 - m11 - m22;
|
||||
const fourYSquaredMinus1 = m11 - m00 - m22;
|
||||
const fourZSquaredMinus1 = m22 - m00 - m11;
|
||||
const fourWSquaredMinus1 = m00 + m11 + m22;
|
||||
let biggestIndex = 0;
|
||||
let fourBiggestSquaredMinus1 = fourWSquaredMinus1;
|
||||
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {
|
||||
fourBiggestSquaredMinus1 = fourXSquaredMinus1;
|
||||
biggestIndex = 1;
|
||||
}
|
||||
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {
|
||||
fourBiggestSquaredMinus1 = fourYSquaredMinus1;
|
||||
biggestIndex = 2;
|
||||
}
|
||||
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {
|
||||
fourBiggestSquaredMinus1 = fourZSquaredMinus1;
|
||||
biggestIndex = 3;
|
||||
}
|
||||
const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5;
|
||||
const mult = 0.25 / biggestVal;
|
||||
const result = new quat();
|
||||
switch (biggestIndex) {
|
||||
case 0:
|
||||
result.w = biggestVal;
|
||||
result.x = (m12 - m21) * mult;
|
||||
result.y = (m20 - m02) * mult;
|
||||
result.z = (m01 - m10) * mult;
|
||||
break;
|
||||
case 1:
|
||||
result.w = (m12 - m21) * mult;
|
||||
result.x = biggestVal;
|
||||
result.y = (m01 + m10) * mult;
|
||||
result.z = (m20 + m02) * mult;
|
||||
break;
|
||||
case 2:
|
||||
result.w = (m20 - m02) * mult;
|
||||
result.x = (m01 + m10) * mult;
|
||||
result.y = biggestVal;
|
||||
result.z = (m12 + m21) * mult;
|
||||
break;
|
||||
case 3:
|
||||
result.w = (m01 - m10) * mult;
|
||||
result.x = (m20 + m02) * mult;
|
||||
result.y = (m12 + m21) * mult;
|
||||
result.z = biggestVal;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
rotate(angle, axis) {
|
||||
let x = axis.x;
|
||||
let y = axis.y;
|
||||
let z = axis.z;
|
||||
let length = Math.sqrt(x * x + y * y + z * z);
|
||||
if (!length) {
|
||||
return null;
|
||||
}
|
||||
if (length !== 1) {
|
||||
length = 1 / length;
|
||||
x *= length;
|
||||
y *= length;
|
||||
z *= length;
|
||||
}
|
||||
const s = Math.sin(angle);
|
||||
const c = Math.cos(angle);
|
||||
const t = 1.0 - c;
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const b00 = x * x * t + c;
|
||||
const b01 = y * x * t + z * s;
|
||||
const b02 = z * x * t - y * s;
|
||||
const b10 = x * y * t - z * s;
|
||||
const b11 = y * y * t + c;
|
||||
const b12 = z * y * t + x * s;
|
||||
const b20 = x * z * t + y * s;
|
||||
const b21 = y * z * t - x * s;
|
||||
const b22 = z * z * t + c;
|
||||
this.values[0] = a00 * b00 + a10 * b01 + a20 * b02;
|
||||
this.values[1] = a01 * b00 + a11 * b01 + a21 * b02;
|
||||
this.values[2] = a02 * b00 + a12 * b01 + a22 * b02;
|
||||
this.values[3] = a00 * b10 + a10 * b11 + a20 * b12;
|
||||
this.values[4] = a01 * b10 + a11 * b11 + a21 * b12;
|
||||
this.values[5] = a02 * b10 + a12 * b11 + a22 * b12;
|
||||
this.values[6] = a00 * b20 + a10 * b21 + a20 * b22;
|
||||
this.values[7] = a01 * b20 + a11 * b21 + a21 * b22;
|
||||
this.values[8] = a02 * b20 + a12 * b21 + a22 * b22;
|
||||
return this;
|
||||
}
|
||||
static product(m1, m2, result) {
|
||||
const a00 = m1.at(0);
|
||||
const a01 = m1.at(1);
|
||||
const a02 = m1.at(2);
|
||||
const a10 = m1.at(3);
|
||||
const a11 = m1.at(4);
|
||||
const a12 = m1.at(5);
|
||||
const a20 = m1.at(6);
|
||||
const a21 = m1.at(7);
|
||||
const a22 = m1.at(8);
|
||||
const b00 = m2.at(0);
|
||||
const b01 = m2.at(1);
|
||||
const b02 = m2.at(2);
|
||||
const b10 = m2.at(3);
|
||||
const b11 = m2.at(4);
|
||||
const b12 = m2.at(5);
|
||||
const b20 = m2.at(6);
|
||||
const b21 = m2.at(7);
|
||||
const b22 = m2.at(8);
|
||||
if (result) {
|
||||
result.init([
|
||||
b00 * a00 + b01 * a10 + b02 * a20,
|
||||
b00 * a01 + b01 * a11 + b02 * a21,
|
||||
b00 * a02 + b01 * a12 + b02 * a22,
|
||||
b10 * a00 + b11 * a10 + b12 * a20,
|
||||
b10 * a01 + b11 * a11 + b12 * a21,
|
||||
b10 * a02 + b11 * a12 + b12 * a22,
|
||||
b20 * a00 + b21 * a10 + b22 * a20,
|
||||
b20 * a01 + b21 * a11 + b22 * a21,
|
||||
b20 * a02 + b21 * a12 + b22 * a22
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new mat3([
|
||||
b00 * a00 + b01 * a10 + b02 * a20,
|
||||
b00 * a01 + b01 * a11 + b02 * a21,
|
||||
b00 * a02 + b01 * a12 + b02 * a22,
|
||||
b10 * a00 + b11 * a10 + b12 * a20,
|
||||
b10 * a01 + b11 * a11 + b12 * a21,
|
||||
b10 * a02 + b11 * a12 + b12 * a22,
|
||||
b20 * a00 + b21 * a10 + b22 * a20,
|
||||
b20 * a01 + b21 * a11 + b22 * a21,
|
||||
b20 * a02 + b21 * a12 + b22 * a22
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mat3.identity = new mat3().setIdentity();
|
33
framework/resonator/vendor/tsm/mat4.d.ts
vendored
Normal file
33
framework/resonator/vendor/tsm/mat4.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import mat3 from './mat3';
|
||||
import vec3 from './vec3';
|
||||
import vec4 from './vec4';
|
||||
export default class mat4 {
|
||||
constructor(values?: number[]);
|
||||
private values;
|
||||
static readonly identity: mat4;
|
||||
at(index: number): number;
|
||||
init(values: number[]): mat4;
|
||||
reset(): void;
|
||||
copy(dest?: mat4): mat4;
|
||||
all(): number[];
|
||||
row(index: number): number[];
|
||||
col(index: number): number[];
|
||||
equals(matrix: mat4, threshold?: number): boolean;
|
||||
determinant(): number;
|
||||
setIdentity(): mat4;
|
||||
transpose(): mat4;
|
||||
inverse(): mat4;
|
||||
multiply(matrix: mat4): mat4;
|
||||
multiplyVec3(vector: vec3): vec3;
|
||||
multiplyVec4(vector: vec4, dest?: vec4): vec4;
|
||||
toMat3(): mat3;
|
||||
toInverseMat3(): mat3;
|
||||
translate(vector: vec3): mat4;
|
||||
scale(vector: vec3): mat4;
|
||||
rotate(angle: number, axis: vec3): mat4;
|
||||
static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4;
|
||||
static perspective(fov: number, aspect: number, near: number, far: number): mat4;
|
||||
static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4;
|
||||
static lookAt(position: vec3, target: vec3, up?: vec3): mat4;
|
||||
static product(m1: mat4, m2: mat4, result: mat4): mat4;
|
||||
}
|
579
framework/resonator/vendor/tsm/mat4.js
vendored
Normal file
579
framework/resonator/vendor/tsm/mat4.js
vendored
Normal file
@@ -0,0 +1,579 @@
|
||||
import mat3 from './mat3';
|
||||
import vec3 from './vec3';
|
||||
import vec4 from './vec4';
|
||||
import { epsilon } from './constants';
|
||||
export default class mat4 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(16);
|
||||
if (values !== undefined) {
|
||||
this.init(values);
|
||||
}
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
init(values) {
|
||||
for (let i = 0; i < 16; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
reset() {
|
||||
for (let i = 0; i < 16; i++) {
|
||||
this.values[i] = 0;
|
||||
}
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new mat4();
|
||||
}
|
||||
for (let i = 0; i < 16; i++) {
|
||||
dest.values[i] = this.values[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
all() {
|
||||
const data = [];
|
||||
for (let i = 0; i < 16; i++) {
|
||||
data[i] = this.values[i];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
row(index) {
|
||||
return [
|
||||
this.values[index * 4 + 0],
|
||||
this.values[index * 4 + 1],
|
||||
this.values[index * 4 + 2],
|
||||
this.values[index * 4 + 3]
|
||||
];
|
||||
}
|
||||
col(index) {
|
||||
return [
|
||||
this.values[index],
|
||||
this.values[index + 4],
|
||||
this.values[index + 8],
|
||||
this.values[index + 12]
|
||||
];
|
||||
}
|
||||
equals(matrix, threshold = epsilon) {
|
||||
for (let i = 0; i < 16; i++) {
|
||||
if (Math.abs(this.values[i] - matrix.at(i)) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
determinant() {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a03 = this.values[3];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a13 = this.values[7];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const a23 = this.values[11];
|
||||
const a30 = this.values[12];
|
||||
const a31 = this.values[13];
|
||||
const a32 = this.values[14];
|
||||
const a33 = this.values[15];
|
||||
const det00 = a00 * a11 - a01 * a10;
|
||||
const det01 = a00 * a12 - a02 * a10;
|
||||
const det02 = a00 * a13 - a03 * a10;
|
||||
const det03 = a01 * a12 - a02 * a11;
|
||||
const det04 = a01 * a13 - a03 * a11;
|
||||
const det05 = a02 * a13 - a03 * a12;
|
||||
const det06 = a20 * a31 - a21 * a30;
|
||||
const det07 = a20 * a32 - a22 * a30;
|
||||
const det08 = a20 * a33 - a23 * a30;
|
||||
const det09 = a21 * a32 - a22 * a31;
|
||||
const det10 = a21 * a33 - a23 * a31;
|
||||
const det11 = a22 * a33 - a23 * a32;
|
||||
return (det00 * det11 -
|
||||
det01 * det10 +
|
||||
det02 * det09 +
|
||||
det03 * det08 -
|
||||
det04 * det07 +
|
||||
det05 * det06);
|
||||
}
|
||||
setIdentity() {
|
||||
this.values[0] = 1;
|
||||
this.values[1] = 0;
|
||||
this.values[2] = 0;
|
||||
this.values[3] = 0;
|
||||
this.values[4] = 0;
|
||||
this.values[5] = 1;
|
||||
this.values[6] = 0;
|
||||
this.values[7] = 0;
|
||||
this.values[8] = 0;
|
||||
this.values[9] = 0;
|
||||
this.values[10] = 1;
|
||||
this.values[11] = 0;
|
||||
this.values[12] = 0;
|
||||
this.values[13] = 0;
|
||||
this.values[14] = 0;
|
||||
this.values[15] = 1;
|
||||
return this;
|
||||
}
|
||||
transpose() {
|
||||
const temp01 = this.values[1];
|
||||
const temp02 = this.values[2];
|
||||
const temp03 = this.values[3];
|
||||
const temp12 = this.values[6];
|
||||
const temp13 = this.values[7];
|
||||
const temp23 = this.values[11];
|
||||
this.values[1] = this.values[4];
|
||||
this.values[2] = this.values[8];
|
||||
this.values[3] = this.values[12];
|
||||
this.values[4] = temp01;
|
||||
this.values[6] = this.values[9];
|
||||
this.values[7] = this.values[13];
|
||||
this.values[8] = temp02;
|
||||
this.values[9] = temp12;
|
||||
this.values[11] = this.values[14];
|
||||
this.values[12] = temp03;
|
||||
this.values[13] = temp13;
|
||||
this.values[14] = temp23;
|
||||
return this;
|
||||
}
|
||||
inverse() {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a03 = this.values[3];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a13 = this.values[7];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const a23 = this.values[11];
|
||||
const a30 = this.values[12];
|
||||
const a31 = this.values[13];
|
||||
const a32 = this.values[14];
|
||||
const a33 = this.values[15];
|
||||
const det00 = a00 * a11 - a01 * a10;
|
||||
const det01 = a00 * a12 - a02 * a10;
|
||||
const det02 = a00 * a13 - a03 * a10;
|
||||
const det03 = a01 * a12 - a02 * a11;
|
||||
const det04 = a01 * a13 - a03 * a11;
|
||||
const det05 = a02 * a13 - a03 * a12;
|
||||
const det06 = a20 * a31 - a21 * a30;
|
||||
const det07 = a20 * a32 - a22 * a30;
|
||||
const det08 = a20 * a33 - a23 * a30;
|
||||
const det09 = a21 * a32 - a22 * a31;
|
||||
const det10 = a21 * a33 - a23 * a31;
|
||||
const det11 = a22 * a33 - a23 * a32;
|
||||
let det = det00 * det11 -
|
||||
det01 * det10 +
|
||||
det02 * det09 +
|
||||
det03 * det08 -
|
||||
det04 * det07 +
|
||||
det05 * det06;
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det;
|
||||
this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det;
|
||||
this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det;
|
||||
this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det;
|
||||
this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det;
|
||||
this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det;
|
||||
this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det;
|
||||
this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det;
|
||||
this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det;
|
||||
this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det;
|
||||
this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det;
|
||||
this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det;
|
||||
this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det;
|
||||
this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det;
|
||||
this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det;
|
||||
this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det;
|
||||
return this;
|
||||
}
|
||||
multiply(matrix) {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a03 = this.values[3];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a13 = this.values[7];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const a23 = this.values[11];
|
||||
const a30 = this.values[12];
|
||||
const a31 = this.values[13];
|
||||
const a32 = this.values[14];
|
||||
const a33 = this.values[15];
|
||||
let b0 = matrix.at(0);
|
||||
let b1 = matrix.at(1);
|
||||
let b2 = matrix.at(2);
|
||||
let b3 = matrix.at(3);
|
||||
this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
||||
this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
||||
this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
||||
this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
||||
b0 = matrix.at(4);
|
||||
b1 = matrix.at(5);
|
||||
b2 = matrix.at(6);
|
||||
b3 = matrix.at(7);
|
||||
this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
||||
this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
||||
this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
||||
this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
||||
b0 = matrix.at(8);
|
||||
b1 = matrix.at(9);
|
||||
b2 = matrix.at(10);
|
||||
b3 = matrix.at(11);
|
||||
this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
||||
this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
||||
this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
||||
this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
||||
b0 = matrix.at(12);
|
||||
b1 = matrix.at(13);
|
||||
b2 = matrix.at(14);
|
||||
b3 = matrix.at(15);
|
||||
this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
|
||||
this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
|
||||
this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
|
||||
this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
|
||||
return this;
|
||||
}
|
||||
multiplyVec3(vector) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
return new vec3([
|
||||
this.values[0] * x +
|
||||
this.values[4] * y +
|
||||
this.values[8] * z +
|
||||
this.values[12],
|
||||
this.values[1] * x +
|
||||
this.values[5] * y +
|
||||
this.values[9] * z +
|
||||
this.values[13],
|
||||
this.values[2] * x +
|
||||
this.values[6] * y +
|
||||
this.values[10] * z +
|
||||
this.values[14]
|
||||
]);
|
||||
}
|
||||
multiplyVec4(vector, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
const w = vector.w;
|
||||
dest.x =
|
||||
this.values[0] * x +
|
||||
this.values[4] * y +
|
||||
this.values[8] * z +
|
||||
this.values[12] * w;
|
||||
dest.y =
|
||||
this.values[1] * x +
|
||||
this.values[5] * y +
|
||||
this.values[9] * z +
|
||||
this.values[13] * w;
|
||||
dest.z =
|
||||
this.values[2] * x +
|
||||
this.values[6] * y +
|
||||
this.values[10] * z +
|
||||
this.values[14] * w;
|
||||
dest.w =
|
||||
this.values[3] * x +
|
||||
this.values[7] * y +
|
||||
this.values[11] * z +
|
||||
this.values[15] * w;
|
||||
return dest;
|
||||
}
|
||||
toMat3() {
|
||||
return new mat3([
|
||||
this.values[0],
|
||||
this.values[1],
|
||||
this.values[2],
|
||||
this.values[4],
|
||||
this.values[5],
|
||||
this.values[6],
|
||||
this.values[8],
|
||||
this.values[9],
|
||||
this.values[10]
|
||||
]);
|
||||
}
|
||||
toInverseMat3() {
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const det01 = a22 * a11 - a12 * a21;
|
||||
const det11 = -a22 * a10 + a12 * a20;
|
||||
const det21 = a21 * a10 - a11 * a20;
|
||||
let det = a00 * det01 + a01 * det11 + a02 * det21;
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
return new mat3([
|
||||
det01 * det,
|
||||
(-a22 * a01 + a02 * a21) * det,
|
||||
(a12 * a01 - a02 * a11) * det,
|
||||
det11 * det,
|
||||
(a22 * a00 - a02 * a20) * det,
|
||||
(-a12 * a00 + a02 * a10) * det,
|
||||
det21 * det,
|
||||
(-a21 * a00 + a01 * a20) * det,
|
||||
(a11 * a00 - a01 * a10) * det
|
||||
]);
|
||||
}
|
||||
translate(vector) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
this.values[12] +=
|
||||
this.values[0] * x + this.values[4] * y + this.values[8] * z;
|
||||
this.values[13] +=
|
||||
this.values[1] * x + this.values[5] * y + this.values[9] * z;
|
||||
this.values[14] +=
|
||||
this.values[2] * x + this.values[6] * y + this.values[10] * z;
|
||||
this.values[15] +=
|
||||
this.values[3] * x + this.values[7] * y + this.values[11] * z;
|
||||
return this;
|
||||
}
|
||||
scale(vector) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
this.values[0] *= x;
|
||||
this.values[1] *= x;
|
||||
this.values[2] *= x;
|
||||
this.values[3] *= x;
|
||||
this.values[4] *= y;
|
||||
this.values[5] *= y;
|
||||
this.values[6] *= y;
|
||||
this.values[7] *= y;
|
||||
this.values[8] *= z;
|
||||
this.values[9] *= z;
|
||||
this.values[10] *= z;
|
||||
this.values[11] *= z;
|
||||
return this;
|
||||
}
|
||||
rotate(angle, axis) {
|
||||
let x = axis.x;
|
||||
let y = axis.y;
|
||||
let z = axis.z;
|
||||
let length = Math.sqrt(x * x + y * y + z * z);
|
||||
if (!length) {
|
||||
return null;
|
||||
}
|
||||
if (length !== 1) {
|
||||
length = 1 / length;
|
||||
x *= length;
|
||||
y *= length;
|
||||
z *= length;
|
||||
}
|
||||
const s = Math.sin(angle);
|
||||
const c = Math.cos(angle);
|
||||
const t = 1.0 - c;
|
||||
const a00 = this.values[0];
|
||||
const a01 = this.values[1];
|
||||
const a02 = this.values[2];
|
||||
const a03 = this.values[3];
|
||||
const a10 = this.values[4];
|
||||
const a11 = this.values[5];
|
||||
const a12 = this.values[6];
|
||||
const a13 = this.values[7];
|
||||
const a20 = this.values[8];
|
||||
const a21 = this.values[9];
|
||||
const a22 = this.values[10];
|
||||
const a23 = this.values[11];
|
||||
const b00 = x * x * t + c;
|
||||
const b01 = y * x * t + z * s;
|
||||
const b02 = z * x * t - y * s;
|
||||
const b10 = x * y * t - z * s;
|
||||
const b11 = y * y * t + c;
|
||||
const b12 = z * y * t + x * s;
|
||||
const b20 = x * z * t + y * s;
|
||||
const b21 = y * z * t - x * s;
|
||||
const b22 = z * z * t + c;
|
||||
this.values[0] = a00 * b00 + a10 * b01 + a20 * b02;
|
||||
this.values[1] = a01 * b00 + a11 * b01 + a21 * b02;
|
||||
this.values[2] = a02 * b00 + a12 * b01 + a22 * b02;
|
||||
this.values[3] = a03 * b00 + a13 * b01 + a23 * b02;
|
||||
this.values[4] = a00 * b10 + a10 * b11 + a20 * b12;
|
||||
this.values[5] = a01 * b10 + a11 * b11 + a21 * b12;
|
||||
this.values[6] = a02 * b10 + a12 * b11 + a22 * b12;
|
||||
this.values[7] = a03 * b10 + a13 * b11 + a23 * b12;
|
||||
this.values[8] = a00 * b20 + a10 * b21 + a20 * b22;
|
||||
this.values[9] = a01 * b20 + a11 * b21 + a21 * b22;
|
||||
this.values[10] = a02 * b20 + a12 * b21 + a22 * b22;
|
||||
this.values[11] = a03 * b20 + a13 * b21 + a23 * b22;
|
||||
return this;
|
||||
}
|
||||
static frustum(left, right, bottom, top, near, far) {
|
||||
const rl = right - left;
|
||||
const tb = top - bottom;
|
||||
const fn = far - near;
|
||||
return new mat4([
|
||||
(near * 2) / rl,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(near * 2) / tb,
|
||||
0,
|
||||
0,
|
||||
(right + left) / rl,
|
||||
(top + bottom) / tb,
|
||||
-(far + near) / fn,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
-(far * near * 2) / fn,
|
||||
0
|
||||
]);
|
||||
}
|
||||
static perspective(fov, aspect, near, far) {
|
||||
const top = near * Math.tan((fov * Math.PI) / 360.0);
|
||||
const right = top * aspect;
|
||||
return mat4.frustum(-right, right, -top, top, near, far);
|
||||
}
|
||||
static orthographic(left, right, bottom, top, near, far) {
|
||||
const rl = right - left;
|
||||
const tb = top - bottom;
|
||||
const fn = far - near;
|
||||
return new mat4([
|
||||
2 / rl,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2 / tb,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
-2 / fn,
|
||||
0,
|
||||
-(left + right) / rl,
|
||||
-(top + bottom) / tb,
|
||||
-(far + near) / fn,
|
||||
1
|
||||
]);
|
||||
}
|
||||
static lookAt(position, target, up = vec3.up) {
|
||||
if (position.equals(target)) {
|
||||
return this.identity;
|
||||
}
|
||||
const z = vec3.difference(position, target).normalize();
|
||||
const x = vec3.cross(up, z).normalize();
|
||||
const y = vec3.cross(z, x).normalize();
|
||||
return new mat4([
|
||||
x.x,
|
||||
y.x,
|
||||
z.x,
|
||||
0,
|
||||
x.y,
|
||||
y.y,
|
||||
z.y,
|
||||
0,
|
||||
x.z,
|
||||
y.z,
|
||||
z.z,
|
||||
0,
|
||||
-vec3.dot(x, position),
|
||||
-vec3.dot(y, position),
|
||||
-vec3.dot(z, position),
|
||||
1
|
||||
]);
|
||||
}
|
||||
static product(m1, m2, result) {
|
||||
const a00 = m1.at(0);
|
||||
const a01 = m1.at(1);
|
||||
const a02 = m1.at(2);
|
||||
const a03 = m1.at(3);
|
||||
const a10 = m1.at(4);
|
||||
const a11 = m1.at(5);
|
||||
const a12 = m1.at(6);
|
||||
const a13 = m1.at(7);
|
||||
const a20 = m1.at(8);
|
||||
const a21 = m1.at(9);
|
||||
const a22 = m1.at(10);
|
||||
const a23 = m1.at(11);
|
||||
const a30 = m1.at(12);
|
||||
const a31 = m1.at(13);
|
||||
const a32 = m1.at(14);
|
||||
const a33 = m1.at(15);
|
||||
const b00 = m2.at(0);
|
||||
const b01 = m2.at(1);
|
||||
const b02 = m2.at(2);
|
||||
const b03 = m2.at(3);
|
||||
const b10 = m2.at(4);
|
||||
const b11 = m2.at(5);
|
||||
const b12 = m2.at(6);
|
||||
const b13 = m2.at(7);
|
||||
const b20 = m2.at(8);
|
||||
const b21 = m2.at(9);
|
||||
const b22 = m2.at(10);
|
||||
const b23 = m2.at(11);
|
||||
const b30 = m2.at(12);
|
||||
const b31 = m2.at(13);
|
||||
const b32 = m2.at(14);
|
||||
const b33 = m2.at(15);
|
||||
if (result) {
|
||||
result.init([
|
||||
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
|
||||
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
|
||||
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
|
||||
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
|
||||
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
|
||||
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
|
||||
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
|
||||
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
|
||||
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
|
||||
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
|
||||
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
|
||||
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
|
||||
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
|
||||
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
|
||||
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
|
||||
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return new mat4([
|
||||
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
|
||||
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
|
||||
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
|
||||
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
|
||||
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
|
||||
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
|
||||
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
|
||||
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
|
||||
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
|
||||
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
|
||||
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
|
||||
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
|
||||
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
|
||||
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
|
||||
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
|
||||
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mat4.identity = new mat4().setIdentity();
|
47
framework/resonator/vendor/tsm/quat.d.ts
vendored
Normal file
47
framework/resonator/vendor/tsm/quat.d.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
import mat3 from './mat3';
|
||||
import mat4 from './mat4';
|
||||
import vec3 from './vec3';
|
||||
export default class quat {
|
||||
get x(): number;
|
||||
get y(): number;
|
||||
get z(): number;
|
||||
get w(): number;
|
||||
get xy(): [number, number];
|
||||
get xyz(): [number, number, number];
|
||||
get xyzw(): [number, number, number, number];
|
||||
set x(value: number);
|
||||
set y(value: number);
|
||||
set z(value: number);
|
||||
set w(value: number);
|
||||
set xy(values: [number, number]);
|
||||
set xyz(values: [number, number, number]);
|
||||
set xyzw(values: [number, number, number, number]);
|
||||
constructor(values?: [number, number, number, number]);
|
||||
private values;
|
||||
static readonly identity: quat;
|
||||
at(index: number): number;
|
||||
reset(): void;
|
||||
copy(dest?: quat): quat;
|
||||
roll(): number;
|
||||
pitch(): number;
|
||||
yaw(): number;
|
||||
equals(vector: quat, threshold?: number): boolean;
|
||||
setIdentity(): quat;
|
||||
calculateW(): quat;
|
||||
inverse(): quat;
|
||||
conjugate(): quat;
|
||||
length(): number;
|
||||
normalize(dest?: quat): quat;
|
||||
add(other: quat): quat;
|
||||
multiply(other: quat): quat;
|
||||
multiplyVec3(vector: vec3, dest?: vec3): vec3;
|
||||
toMat3(dest?: mat3): mat3;
|
||||
toMat4(dest?: mat4): mat4;
|
||||
static dot(q1: quat, q2: quat): number;
|
||||
static sum(q1: quat, q2: quat, dest?: quat): quat;
|
||||
static product(q1: quat, q2: quat, dest?: quat): quat;
|
||||
static cross(q1: quat, q2: quat, dest?: quat): quat;
|
||||
static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat;
|
||||
static mix(q1: quat, q2: quat, time: number, dest?: quat): quat;
|
||||
static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat;
|
||||
}
|
404
framework/resonator/vendor/tsm/quat.js
vendored
Normal file
404
framework/resonator/vendor/tsm/quat.js
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
import mat3 from './mat3';
|
||||
import mat4 from './mat4';
|
||||
import vec3 from './vec3';
|
||||
import { epsilon } from './constants';
|
||||
export default class quat {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(4);
|
||||
if (values !== undefined) {
|
||||
this.xyzw = values;
|
||||
}
|
||||
}
|
||||
get x() {
|
||||
return this.values[0];
|
||||
}
|
||||
get y() {
|
||||
return this.values[1];
|
||||
}
|
||||
get z() {
|
||||
return this.values[2];
|
||||
}
|
||||
get w() {
|
||||
return this.values[3];
|
||||
}
|
||||
get xy() {
|
||||
return [this.values[0], this.values[1]];
|
||||
}
|
||||
get xyz() {
|
||||
return [this.values[0], this.values[1], this.values[2]];
|
||||
}
|
||||
get xyzw() {
|
||||
return [this.values[0], this.values[1], this.values[2], this.values[3]];
|
||||
}
|
||||
set x(value) {
|
||||
this.values[0] = value;
|
||||
}
|
||||
set y(value) {
|
||||
this.values[1] = value;
|
||||
}
|
||||
set z(value) {
|
||||
this.values[2] = value;
|
||||
}
|
||||
set w(value) {
|
||||
this.values[3] = value;
|
||||
}
|
||||
set xy(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
}
|
||||
set xyz(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
}
|
||||
set xyzw(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
this.values[3] = values[3];
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
reset() {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
this.values[i] = 0;
|
||||
}
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
for (let i = 0; i < 4; i++) {
|
||||
dest.values[i] = this.values[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
roll() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z);
|
||||
}
|
||||
pitch() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z);
|
||||
}
|
||||
yaw() {
|
||||
return Math.asin(2.0 * (this.x * this.z - this.w * this.y));
|
||||
}
|
||||
equals(vector, threshold = epsilon) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (Math.abs(this.values[i] - vector.at(i)) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
setIdentity() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
this.w = 1;
|
||||
return this;
|
||||
}
|
||||
calculateW() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
|
||||
return this;
|
||||
}
|
||||
inverse() {
|
||||
const dot = quat.dot(this, this);
|
||||
if (!dot) {
|
||||
this.xyzw = [0, 0, 0, 0];
|
||||
return this;
|
||||
}
|
||||
const invDot = dot ? 1.0 / dot : 0;
|
||||
this.x *= -invDot;
|
||||
this.y *= -invDot;
|
||||
this.z *= -invDot;
|
||||
this.w *= invDot;
|
||||
return this;
|
||||
}
|
||||
conjugate() {
|
||||
this.values[0] *= -1;
|
||||
this.values[1] *= -1;
|
||||
this.values[2] *= -1;
|
||||
return this;
|
||||
}
|
||||
length() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
return Math.sqrt(x * x + y * y + z * z + w * w);
|
||||
}
|
||||
normalize(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
let length = Math.sqrt(x * x + y * y + z * z + w * w);
|
||||
if (!length) {
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
dest.z = 0;
|
||||
dest.w = 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1 / length;
|
||||
dest.x = x * length;
|
||||
dest.y = y * length;
|
||||
dest.z = z * length;
|
||||
dest.w = w * length;
|
||||
return dest;
|
||||
}
|
||||
add(other) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
this.values[i] += other.at(i);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
multiply(other) {
|
||||
const q1x = this.values[0];
|
||||
const q1y = this.values[1];
|
||||
const q1z = this.values[2];
|
||||
const q1w = this.values[3];
|
||||
const q2x = other.x;
|
||||
const q2y = other.y;
|
||||
const q2z = other.z;
|
||||
const q2w = other.w;
|
||||
this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y;
|
||||
this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z;
|
||||
this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x;
|
||||
this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
|
||||
return this;
|
||||
}
|
||||
multiplyVec3(vector, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
const qx = this.x;
|
||||
const qy = this.y;
|
||||
const qz = this.z;
|
||||
const qw = this.w;
|
||||
const ix = qw * x + qy * z - qz * y;
|
||||
const iy = qw * y + qz * x - qx * z;
|
||||
const iz = qw * z + qx * y - qy * x;
|
||||
const iw = -qx * x - qy * y - qz * z;
|
||||
dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
||||
dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
||||
dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
||||
return dest;
|
||||
}
|
||||
toMat3(dest) {
|
||||
if (!dest) {
|
||||
dest = new mat3();
|
||||
}
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
const x2 = x + x;
|
||||
const y2 = y + y;
|
||||
const z2 = z + z;
|
||||
const xx = x * x2;
|
||||
const xy = x * y2;
|
||||
const xz = x * z2;
|
||||
const yy = y * y2;
|
||||
const yz = y * z2;
|
||||
const zz = z * z2;
|
||||
const wx = w * x2;
|
||||
const wy = w * y2;
|
||||
const wz = w * z2;
|
||||
dest.init([
|
||||
1 - (yy + zz),
|
||||
xy + wz,
|
||||
xz - wy,
|
||||
xy - wz,
|
||||
1 - (xx + zz),
|
||||
yz + wx,
|
||||
xz + wy,
|
||||
yz - wx,
|
||||
1 - (xx + yy)
|
||||
]);
|
||||
return dest;
|
||||
}
|
||||
toMat4(dest) {
|
||||
if (!dest) {
|
||||
dest = new mat4();
|
||||
}
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
const x2 = x + x;
|
||||
const y2 = y + y;
|
||||
const z2 = z + z;
|
||||
const xx = x * x2;
|
||||
const xy = x * y2;
|
||||
const xz = x * z2;
|
||||
const yy = y * y2;
|
||||
const yz = y * z2;
|
||||
const zz = z * z2;
|
||||
const wx = w * x2;
|
||||
const wy = w * y2;
|
||||
const wz = w * z2;
|
||||
dest.init([
|
||||
1 - (yy + zz),
|
||||
xy + wz,
|
||||
xz - wy,
|
||||
0,
|
||||
xy - wz,
|
||||
1 - (xx + zz),
|
||||
yz + wx,
|
||||
0,
|
||||
xz + wy,
|
||||
yz - wx,
|
||||
1 - (xx + yy),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
]);
|
||||
return dest;
|
||||
}
|
||||
static dot(q1, q2) {
|
||||
return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
|
||||
}
|
||||
static sum(q1, q2, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
dest.x = q1.x + q2.x;
|
||||
dest.y = q1.y + q2.y;
|
||||
dest.z = q1.z + q2.z;
|
||||
dest.w = q1.w + q2.w;
|
||||
return dest;
|
||||
}
|
||||
static product(q1, q2, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
const q1x = q1.x;
|
||||
const q1y = q1.y;
|
||||
const q1z = q1.z;
|
||||
const q1w = q1.w;
|
||||
const q2x = q2.x;
|
||||
const q2y = q2.y;
|
||||
const q2z = q2.z;
|
||||
const q2w = q2.w;
|
||||
dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y;
|
||||
dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z;
|
||||
dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x;
|
||||
dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
|
||||
return dest;
|
||||
}
|
||||
static cross(q1, q2, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
const q1x = q1.x;
|
||||
const q1y = q1.y;
|
||||
const q1z = q1.z;
|
||||
const q1w = q1.w;
|
||||
const q2x = q2.x;
|
||||
const q2y = q2.y;
|
||||
const q2z = q2.z;
|
||||
const q2w = q2.w;
|
||||
dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x;
|
||||
dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
|
||||
dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y;
|
||||
dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z;
|
||||
return dest;
|
||||
}
|
||||
static shortMix(q1, q2, time, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
if (time <= 0.0) {
|
||||
dest.xyzw = q1.xyzw;
|
||||
return dest;
|
||||
}
|
||||
else if (time >= 1.0) {
|
||||
dest.xyzw = q2.xyzw;
|
||||
return dest;
|
||||
}
|
||||
let cos = quat.dot(q1, q2);
|
||||
const q2a = q2.copy();
|
||||
if (cos < 0.0) {
|
||||
q2a.inverse();
|
||||
cos = -cos;
|
||||
}
|
||||
let k0;
|
||||
let k1;
|
||||
if (cos > 0.9999) {
|
||||
k0 = 1 - time;
|
||||
k1 = 0 + time;
|
||||
}
|
||||
else {
|
||||
const sin = Math.sqrt(1 - cos * cos);
|
||||
const angle = Math.atan2(sin, cos);
|
||||
const oneOverSin = 1 / sin;
|
||||
k0 = Math.sin((1 - time) * angle) * oneOverSin;
|
||||
k1 = Math.sin((0 + time) * angle) * oneOverSin;
|
||||
}
|
||||
dest.x = k0 * q1.x + k1 * q2a.x;
|
||||
dest.y = k0 * q1.y + k1 * q2a.y;
|
||||
dest.z = k0 * q1.z + k1 * q2a.z;
|
||||
dest.w = k0 * q1.w + k1 * q2a.w;
|
||||
return dest;
|
||||
}
|
||||
static mix(q1, q2, time, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
|
||||
if (Math.abs(cosHalfTheta) >= 1.0) {
|
||||
dest.xyzw = q1.xyzw;
|
||||
return dest;
|
||||
}
|
||||
const halfTheta = Math.acos(cosHalfTheta);
|
||||
const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
|
||||
if (Math.abs(sinHalfTheta) < 0.001) {
|
||||
dest.x = q1.x * 0.5 + q2.x * 0.5;
|
||||
dest.y = q1.y * 0.5 + q2.y * 0.5;
|
||||
dest.z = q1.z * 0.5 + q2.z * 0.5;
|
||||
dest.w = q1.w * 0.5 + q2.w * 0.5;
|
||||
return dest;
|
||||
}
|
||||
const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta;
|
||||
const ratioB = Math.sin(time * halfTheta) / sinHalfTheta;
|
||||
dest.x = q1.x * ratioA + q2.x * ratioB;
|
||||
dest.y = q1.y * ratioA + q2.y * ratioB;
|
||||
dest.z = q1.z * ratioA + q2.z * ratioB;
|
||||
dest.w = q1.w * ratioA + q2.w * ratioB;
|
||||
return dest;
|
||||
}
|
||||
static fromAxisAngle(axis, angle, dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
angle *= 0.5;
|
||||
const sin = Math.sin(angle);
|
||||
dest.x = axis.x * sin;
|
||||
dest.y = axis.y * sin;
|
||||
dest.z = axis.z * sin;
|
||||
dest.w = Math.cos(angle);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
quat.identity = new quat().setIdentity();
|
17
framework/resonator/vendor/tsm/tsm.d.ts
vendored
Normal file
17
framework/resonator/vendor/tsm/tsm.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import mat2 from './mat2';
|
||||
import mat3 from './mat3';
|
||||
import mat4 from './mat4';
|
||||
import quat from './quat';
|
||||
import vec2 from './vec2';
|
||||
import vec3 from './vec3';
|
||||
import vec4 from './vec4';
|
||||
declare const _default: {
|
||||
vec2: typeof vec2;
|
||||
vec3: typeof vec3;
|
||||
vec4: typeof vec4;
|
||||
mat2: typeof mat2;
|
||||
mat3: typeof mat3;
|
||||
mat4: typeof mat4;
|
||||
quat: typeof quat;
|
||||
};
|
||||
export default _default;
|
40
framework/resonator/vendor/tsm/tsm.js
vendored
Normal file
40
framework/resonator/vendor/tsm/tsm.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018 Matthias Ferch
|
||||
*
|
||||
* Project homepage: https://github.com/matthiasferch/tsm
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
import mat2 from './mat2';
|
||||
import mat3 from './mat3';
|
||||
import mat4 from './mat4';
|
||||
import quat from './quat';
|
||||
import vec2 from './vec2';
|
||||
import vec3 from './vec3';
|
||||
import vec4 from './vec4';
|
||||
export default {
|
||||
vec2,
|
||||
vec3,
|
||||
vec4,
|
||||
mat2,
|
||||
mat3,
|
||||
mat4,
|
||||
quat
|
||||
};
|
40
framework/resonator/vendor/tsm/vec2.d.ts
vendored
Normal file
40
framework/resonator/vendor/tsm/vec2.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import mat2 from './mat2';
|
||||
import mat3 from './mat3';
|
||||
import vec3 from './vec3';
|
||||
export default class vec2 {
|
||||
get x(): number;
|
||||
get y(): number;
|
||||
get xy(): [number, number];
|
||||
set x(value: number);
|
||||
set y(value: number);
|
||||
set xy(values: [number, number]);
|
||||
constructor(values?: [number, number]);
|
||||
private values;
|
||||
static readonly zero: vec2;
|
||||
static readonly one: vec2;
|
||||
at(index: number): number;
|
||||
reset(): void;
|
||||
copy(dest?: vec2): vec2;
|
||||
negate(dest?: vec2): vec2;
|
||||
equals(vector: vec2, threshold?: number): boolean;
|
||||
length(): number;
|
||||
squaredLength(): number;
|
||||
add(vector: vec2): vec2;
|
||||
subtract(vector: vec2): vec2;
|
||||
multiply(vector: vec2): vec2;
|
||||
divide(vector: vec2): vec2;
|
||||
scale(value: number, dest?: vec2): vec2;
|
||||
normalize(dest?: vec2): vec2;
|
||||
multiplyMat2(matrix: mat2, dest?: vec2): vec2;
|
||||
multiplyMat3(matrix: mat3, dest?: vec2): vec2;
|
||||
static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3;
|
||||
static dot(vector: vec2, vector2: vec2): number;
|
||||
static distance(vector: vec2, vector2: vec2): number;
|
||||
static squaredDistance(vector: vec2, vector2: vec2): number;
|
||||
static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2;
|
||||
static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2;
|
||||
static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2;
|
||||
static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2;
|
||||
static product(vector: vec2, vector2: vec2, dest?: vec2): vec2;
|
||||
static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2;
|
||||
}
|
215
framework/resonator/vendor/tsm/vec2.js
vendored
Normal file
215
framework/resonator/vendor/tsm/vec2.js
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
import vec3 from './vec3';
|
||||
import { epsilon } from './constants';
|
||||
export default class vec2 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(2);
|
||||
if (values !== undefined) {
|
||||
this.xy = values;
|
||||
}
|
||||
}
|
||||
get x() {
|
||||
return this.values[0];
|
||||
}
|
||||
get y() {
|
||||
return this.values[1];
|
||||
}
|
||||
get xy() {
|
||||
return [this.values[0], this.values[1]];
|
||||
}
|
||||
set x(value) {
|
||||
this.values[0] = value;
|
||||
}
|
||||
set y(value) {
|
||||
this.values[1] = value;
|
||||
}
|
||||
set xy(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
reset() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
dest.x = this.x;
|
||||
dest.y = this.y;
|
||||
return dest;
|
||||
}
|
||||
negate(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x = -this.x;
|
||||
dest.y = -this.y;
|
||||
return dest;
|
||||
}
|
||||
equals(vector, threshold = epsilon) {
|
||||
if (Math.abs(this.x - vector.x) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.y - vector.y) > threshold) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
length() {
|
||||
return Math.sqrt(this.squaredLength());
|
||||
}
|
||||
squaredLength() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
return x * x + y * y;
|
||||
}
|
||||
add(vector) {
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
return this;
|
||||
}
|
||||
subtract(vector) {
|
||||
this.x -= vector.x;
|
||||
this.y -= vector.y;
|
||||
return this;
|
||||
}
|
||||
multiply(vector) {
|
||||
this.x *= vector.x;
|
||||
this.y *= vector.y;
|
||||
return this;
|
||||
}
|
||||
divide(vector) {
|
||||
this.x /= vector.x;
|
||||
this.y /= vector.y;
|
||||
return this;
|
||||
}
|
||||
scale(value, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x *= value;
|
||||
dest.y *= value;
|
||||
return dest;
|
||||
}
|
||||
normalize(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
let length = this.length();
|
||||
if (length === 1) {
|
||||
return this;
|
||||
}
|
||||
if (length === 0) {
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1.0 / length;
|
||||
dest.x *= length;
|
||||
dest.y *= length;
|
||||
return dest;
|
||||
}
|
||||
multiplyMat2(matrix, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
return matrix.multiplyVec2(this, dest);
|
||||
}
|
||||
multiplyMat3(matrix, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
return matrix.multiplyVec2(this, dest);
|
||||
}
|
||||
static cross(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const x2 = vector2.x;
|
||||
const y2 = vector2.y;
|
||||
const z = x * y2 - y * x2;
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
dest.z = z;
|
||||
return dest;
|
||||
}
|
||||
static dot(vector, vector2) {
|
||||
return vector.x * vector2.x + vector.y * vector2.y;
|
||||
}
|
||||
static distance(vector, vector2) {
|
||||
return Math.sqrt(this.squaredDistance(vector, vector2));
|
||||
}
|
||||
static squaredDistance(vector, vector2) {
|
||||
const x = vector2.x - vector.x;
|
||||
const y = vector2.y - vector.y;
|
||||
return x * x + y * y;
|
||||
}
|
||||
static direction(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
const x = vector.x - vector2.x;
|
||||
const y = vector.y - vector2.y;
|
||||
let length = Math.sqrt(x * x + y * y);
|
||||
if (length === 0) {
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1 / length;
|
||||
dest.x = x * length;
|
||||
dest.y = y * length;
|
||||
return dest;
|
||||
}
|
||||
static mix(vector, vector2, time, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const x2 = vector2.x;
|
||||
const y2 = vector2.y;
|
||||
dest.x = x + time * (x2 - x);
|
||||
dest.y = y + time * (y2 - y);
|
||||
return dest;
|
||||
}
|
||||
static sum(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
dest.x = vector.x + vector2.x;
|
||||
dest.y = vector.y + vector2.y;
|
||||
return dest;
|
||||
}
|
||||
static difference(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
dest.x = vector.x - vector2.x;
|
||||
dest.y = vector.y - vector2.y;
|
||||
return dest;
|
||||
}
|
||||
static product(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
dest.x = vector.x * vector2.x;
|
||||
dest.y = vector.y * vector2.y;
|
||||
return dest;
|
||||
}
|
||||
static quotient(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec2();
|
||||
}
|
||||
dest.x = vector.x / vector2.x;
|
||||
dest.y = vector.y / vector2.y;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
vec2.zero = new vec2([0, 0]);
|
||||
vec2.one = new vec2([1, 1]);
|
47
framework/resonator/vendor/tsm/vec3.d.ts
vendored
Normal file
47
framework/resonator/vendor/tsm/vec3.d.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
import mat3 from './mat3';
|
||||
import quat from './quat';
|
||||
export default class vec3 {
|
||||
get x(): number;
|
||||
get y(): number;
|
||||
get z(): number;
|
||||
get xy(): [number, number];
|
||||
get xyz(): [number, number, number];
|
||||
set x(value: number);
|
||||
set y(value: number);
|
||||
set z(value: number);
|
||||
set xy(values: [number, number]);
|
||||
set xyz(values: [number, number, number]);
|
||||
constructor(values?: [number, number, number]);
|
||||
private values;
|
||||
static readonly zero: vec3;
|
||||
static readonly one: vec3;
|
||||
static readonly up: vec3;
|
||||
static readonly right: vec3;
|
||||
static readonly forward: vec3;
|
||||
at(index: number): number;
|
||||
reset(): void;
|
||||
copy(dest?: vec3): vec3;
|
||||
negate(dest?: vec3): vec3;
|
||||
equals(vector: vec3, threshold?: number): boolean;
|
||||
length(): number;
|
||||
squaredLength(): number;
|
||||
add(vector: vec3): vec3;
|
||||
subtract(vector: vec3): vec3;
|
||||
multiply(vector: vec3): vec3;
|
||||
divide(vector: vec3): vec3;
|
||||
scale(value: number, dest?: vec3): vec3;
|
||||
normalize(dest?: vec3): vec3;
|
||||
multiplyByMat3(matrix: mat3, dest?: vec3): vec3;
|
||||
multiplyByQuat(quaternion: quat, dest?: vec3): vec3;
|
||||
toQuat(dest?: quat): quat;
|
||||
static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static dot(vector: vec3, vector2: vec3): number;
|
||||
static distance(vector: vec3, vector2: vec3): number;
|
||||
static squaredDistance(vector: vec3, vector2: vec3): number;
|
||||
static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3;
|
||||
static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static product(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
}
|
279
framework/resonator/vendor/tsm/vec3.js
vendored
Normal file
279
framework/resonator/vendor/tsm/vec3.js
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
import quat from './quat';
|
||||
import { epsilon } from './constants';
|
||||
export default class vec3 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(3);
|
||||
if (values !== undefined) {
|
||||
this.xyz = values;
|
||||
}
|
||||
}
|
||||
get x() {
|
||||
return this.values[0];
|
||||
}
|
||||
get y() {
|
||||
return this.values[1];
|
||||
}
|
||||
get z() {
|
||||
return this.values[2];
|
||||
}
|
||||
get xy() {
|
||||
return [this.values[0], this.values[1]];
|
||||
}
|
||||
get xyz() {
|
||||
return [this.values[0], this.values[1], this.values[2]];
|
||||
}
|
||||
set x(value) {
|
||||
this.values[0] = value;
|
||||
}
|
||||
set y(value) {
|
||||
this.values[1] = value;
|
||||
}
|
||||
set z(value) {
|
||||
this.values[2] = value;
|
||||
}
|
||||
set xy(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
}
|
||||
set xyz(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
reset() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = this.x;
|
||||
dest.y = this.y;
|
||||
dest.z = this.z;
|
||||
return dest;
|
||||
}
|
||||
negate(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x = -this.x;
|
||||
dest.y = -this.y;
|
||||
dest.z = -this.z;
|
||||
return dest;
|
||||
}
|
||||
equals(vector, threshold = epsilon) {
|
||||
if (Math.abs(this.x - vector.x) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.y - vector.y) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.z - vector.z) > threshold) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
length() {
|
||||
return Math.sqrt(this.squaredLength());
|
||||
}
|
||||
squaredLength() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
add(vector) {
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
this.z += vector.z;
|
||||
return this;
|
||||
}
|
||||
subtract(vector) {
|
||||
this.x -= vector.x;
|
||||
this.y -= vector.y;
|
||||
this.z -= vector.z;
|
||||
return this;
|
||||
}
|
||||
multiply(vector) {
|
||||
this.x *= vector.x;
|
||||
this.y *= vector.y;
|
||||
this.z *= vector.z;
|
||||
return this;
|
||||
}
|
||||
divide(vector) {
|
||||
this.x /= vector.x;
|
||||
this.y /= vector.y;
|
||||
this.z /= vector.z;
|
||||
return this;
|
||||
}
|
||||
scale(value, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x *= value;
|
||||
dest.y *= value;
|
||||
dest.z *= value;
|
||||
return dest;
|
||||
}
|
||||
normalize(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
let length = this.length();
|
||||
if (length === 1) {
|
||||
return this;
|
||||
}
|
||||
if (length === 0) {
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
dest.z = 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1.0 / length;
|
||||
dest.x *= length;
|
||||
dest.y *= length;
|
||||
dest.z *= length;
|
||||
return dest;
|
||||
}
|
||||
multiplyByMat3(matrix, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
return matrix.multiplyVec3(this, dest);
|
||||
}
|
||||
multiplyByQuat(quaternion, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
return quaternion.multiplyVec3(this, dest);
|
||||
}
|
||||
toQuat(dest) {
|
||||
if (!dest) {
|
||||
dest = new quat();
|
||||
}
|
||||
const c = new vec3();
|
||||
const s = new vec3();
|
||||
c.x = Math.cos(this.x * 0.5);
|
||||
s.x = Math.sin(this.x * 0.5);
|
||||
c.y = Math.cos(this.y * 0.5);
|
||||
s.y = Math.sin(this.y * 0.5);
|
||||
c.z = Math.cos(this.z * 0.5);
|
||||
s.z = Math.sin(this.z * 0.5);
|
||||
dest.x = s.x * c.y * c.z - c.x * s.y * s.z;
|
||||
dest.y = c.x * s.y * c.z + s.x * c.y * s.z;
|
||||
dest.z = c.x * c.y * s.z - s.x * s.y * c.z;
|
||||
dest.w = c.x * c.y * c.z + s.x * s.y * s.z;
|
||||
return dest;
|
||||
}
|
||||
static cross(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
const x2 = vector2.x;
|
||||
const y2 = vector2.y;
|
||||
const z2 = vector2.z;
|
||||
dest.x = y * z2 - z * y2;
|
||||
dest.y = z * x2 - x * z2;
|
||||
dest.z = x * y2 - y * x2;
|
||||
return dest;
|
||||
}
|
||||
static dot(vector, vector2) {
|
||||
const x = vector.x;
|
||||
const y = vector.y;
|
||||
const z = vector.z;
|
||||
const x2 = vector2.x;
|
||||
const y2 = vector2.y;
|
||||
const z2 = vector2.z;
|
||||
return x * x2 + y * y2 + z * z2;
|
||||
}
|
||||
static distance(vector, vector2) {
|
||||
const x = vector2.x - vector.x;
|
||||
const y = vector2.y - vector.y;
|
||||
const z = vector2.z - vector.z;
|
||||
return Math.sqrt(this.squaredDistance(vector, vector2));
|
||||
}
|
||||
static squaredDistance(vector, vector2) {
|
||||
const x = vector2.x - vector.x;
|
||||
const y = vector2.y - vector.y;
|
||||
const z = vector2.z - vector.z;
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
static direction(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
const x = vector.x - vector2.x;
|
||||
const y = vector.y - vector2.y;
|
||||
const z = vector.z - vector2.z;
|
||||
let length = Math.sqrt(x * x + y * y + z * z);
|
||||
if (length === 0) {
|
||||
dest.x = 0;
|
||||
dest.y = 0;
|
||||
dest.z = 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1 / length;
|
||||
dest.x = x * length;
|
||||
dest.y = y * length;
|
||||
dest.z = z * length;
|
||||
return dest;
|
||||
}
|
||||
static mix(vector, vector2, time, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = vector.x + time * (vector2.x - vector.x);
|
||||
dest.y = vector.y + time * (vector2.y - vector.y);
|
||||
dest.z = vector.z + time * (vector2.z - vector.z);
|
||||
return dest;
|
||||
}
|
||||
static sum(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = vector.x + vector2.x;
|
||||
dest.y = vector.y + vector2.y;
|
||||
dest.z = vector.z + vector2.z;
|
||||
return dest;
|
||||
}
|
||||
static difference(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = vector.x - vector2.x;
|
||||
dest.y = vector.y - vector2.y;
|
||||
dest.z = vector.z - vector2.z;
|
||||
return dest;
|
||||
}
|
||||
static product(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = vector.x * vector2.x;
|
||||
dest.y = vector.y * vector2.y;
|
||||
dest.z = vector.z * vector2.z;
|
||||
return dest;
|
||||
}
|
||||
static quotient(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
}
|
||||
dest.x = vector.x / vector2.x;
|
||||
dest.y = vector.y / vector2.y;
|
||||
dest.z = vector.z / vector2.z;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
vec3.zero = new vec3([0, 0, 0]);
|
||||
vec3.one = new vec3([1, 1, 1]);
|
||||
vec3.up = new vec3([0, 1, 0]);
|
||||
vec3.right = new vec3([1, 0, 0]);
|
||||
vec3.forward = new vec3([0, 0, 1]);
|
54
framework/resonator/vendor/tsm/vec4.d.ts
vendored
Normal file
54
framework/resonator/vendor/tsm/vec4.d.ts
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import mat4 from './mat4';
|
||||
export default class vec4 {
|
||||
get x(): number;
|
||||
get y(): number;
|
||||
get z(): number;
|
||||
get w(): number;
|
||||
get xy(): [number, number];
|
||||
get xyz(): [number, number, number];
|
||||
get xyzw(): [number, number, number, number];
|
||||
set x(value: number);
|
||||
set y(value: number);
|
||||
set z(value: number);
|
||||
set w(value: number);
|
||||
set xy(values: [number, number]);
|
||||
set xyz(values: [number, number, number]);
|
||||
set xyzw(values: [number, number, number, number]);
|
||||
get r(): number;
|
||||
get g(): number;
|
||||
get b(): number;
|
||||
get a(): number;
|
||||
get rg(): [number, number];
|
||||
get rgb(): [number, number, number];
|
||||
get rgba(): [number, number, number, number];
|
||||
set r(value: number);
|
||||
set g(value: number);
|
||||
set b(value: number);
|
||||
set a(value: number);
|
||||
set rg(values: [number, number]);
|
||||
set rgb(values: [number, number, number]);
|
||||
set rgba(values: [number, number, number, number]);
|
||||
constructor(values?: [number, number, number, number]);
|
||||
private values;
|
||||
static readonly zero: vec4;
|
||||
static readonly one: vec4;
|
||||
at(index: number): number;
|
||||
reset(): void;
|
||||
copy(dest?: vec4): vec4;
|
||||
negate(dest?: vec4): vec4;
|
||||
equals(vector: vec4, threshold?: number): boolean;
|
||||
length(): number;
|
||||
squaredLength(): number;
|
||||
add(vector: vec4): vec4;
|
||||
subtract(vector: vec4): vec4;
|
||||
multiply(vector: vec4): vec4;
|
||||
divide(vector: vec4): vec4;
|
||||
scale(value: number, dest?: vec4): vec4;
|
||||
normalize(dest?: vec4): vec4;
|
||||
multiplyMat4(matrix: mat4, dest?: vec4): vec4;
|
||||
static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4;
|
||||
static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4;
|
||||
static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4;
|
||||
static product(vector: vec4, vector2: vec4, dest?: vec4): vec4;
|
||||
static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4;
|
||||
}
|
277
framework/resonator/vendor/tsm/vec4.js
vendored
Normal file
277
framework/resonator/vendor/tsm/vec4.js
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
import { epsilon } from './constants';
|
||||
export default class vec4 {
|
||||
constructor(values) {
|
||||
this.values = new Float32Array(4);
|
||||
if (values !== undefined) {
|
||||
this.xyzw = values;
|
||||
}
|
||||
}
|
||||
get x() {
|
||||
return this.values[0];
|
||||
}
|
||||
get y() {
|
||||
return this.values[1];
|
||||
}
|
||||
get z() {
|
||||
return this.values[2];
|
||||
}
|
||||
get w() {
|
||||
return this.values[3];
|
||||
}
|
||||
get xy() {
|
||||
return [this.values[0], this.values[1]];
|
||||
}
|
||||
get xyz() {
|
||||
return [this.values[0], this.values[1], this.values[2]];
|
||||
}
|
||||
get xyzw() {
|
||||
return [this.values[0], this.values[1], this.values[2], this.values[3]];
|
||||
}
|
||||
set x(value) {
|
||||
this.values[0] = value;
|
||||
}
|
||||
set y(value) {
|
||||
this.values[1] = value;
|
||||
}
|
||||
set z(value) {
|
||||
this.values[2] = value;
|
||||
}
|
||||
set w(value) {
|
||||
this.values[3] = value;
|
||||
}
|
||||
set xy(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
}
|
||||
set xyz(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
}
|
||||
set xyzw(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
this.values[3] = values[3];
|
||||
}
|
||||
get r() {
|
||||
return this.values[0];
|
||||
}
|
||||
get g() {
|
||||
return this.values[1];
|
||||
}
|
||||
get b() {
|
||||
return this.values[2];
|
||||
}
|
||||
get a() {
|
||||
return this.values[3];
|
||||
}
|
||||
get rg() {
|
||||
return [this.values[0], this.values[1]];
|
||||
}
|
||||
get rgb() {
|
||||
return [this.values[0], this.values[1], this.values[2]];
|
||||
}
|
||||
get rgba() {
|
||||
return [this.values[0], this.values[1], this.values[2], this.values[3]];
|
||||
}
|
||||
set r(value) {
|
||||
this.values[0] = value;
|
||||
}
|
||||
set g(value) {
|
||||
this.values[1] = value;
|
||||
}
|
||||
set b(value) {
|
||||
this.values[2] = value;
|
||||
}
|
||||
set a(value) {
|
||||
this.values[3] = value;
|
||||
}
|
||||
set rg(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
}
|
||||
set rgb(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
}
|
||||
set rgba(values) {
|
||||
this.values[0] = values[0];
|
||||
this.values[1] = values[1];
|
||||
this.values[2] = values[2];
|
||||
this.values[3] = values[3];
|
||||
}
|
||||
at(index) {
|
||||
return this.values[index];
|
||||
}
|
||||
reset() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
this.w = 0;
|
||||
}
|
||||
copy(dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = this.x;
|
||||
dest.y = this.y;
|
||||
dest.z = this.z;
|
||||
dest.w = this.w;
|
||||
return dest;
|
||||
}
|
||||
negate(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x = -this.x;
|
||||
dest.y = -this.y;
|
||||
dest.z = -this.z;
|
||||
dest.w = -this.w;
|
||||
return dest;
|
||||
}
|
||||
equals(vector, threshold = epsilon) {
|
||||
if (Math.abs(this.x - vector.x) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.y - vector.y) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.z - vector.z) > threshold) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(this.w - vector.w) > threshold) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
length() {
|
||||
return Math.sqrt(this.squaredLength());
|
||||
}
|
||||
squaredLength() {
|
||||
const x = this.x;
|
||||
const y = this.y;
|
||||
const z = this.z;
|
||||
const w = this.w;
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
add(vector) {
|
||||
this.x += vector.x;
|
||||
this.y += vector.y;
|
||||
this.z += vector.z;
|
||||
this.w += vector.w;
|
||||
return this;
|
||||
}
|
||||
subtract(vector) {
|
||||
this.x -= vector.x;
|
||||
this.y -= vector.y;
|
||||
this.z -= vector.z;
|
||||
this.w -= vector.w;
|
||||
return this;
|
||||
}
|
||||
multiply(vector) {
|
||||
this.x *= vector.x;
|
||||
this.y *= vector.y;
|
||||
this.z *= vector.z;
|
||||
this.w *= vector.w;
|
||||
return this;
|
||||
}
|
||||
divide(vector) {
|
||||
this.x /= vector.x;
|
||||
this.y /= vector.y;
|
||||
this.z /= vector.z;
|
||||
this.w /= vector.w;
|
||||
return this;
|
||||
}
|
||||
scale(value, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
dest.x *= value;
|
||||
dest.y *= value;
|
||||
dest.z *= value;
|
||||
dest.w *= value;
|
||||
return dest;
|
||||
}
|
||||
normalize(dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
let length = this.length();
|
||||
if (length === 1) {
|
||||
return this;
|
||||
}
|
||||
if (length === 0) {
|
||||
dest.x *= 0;
|
||||
dest.y *= 0;
|
||||
dest.z *= 0;
|
||||
dest.w *= 0;
|
||||
return dest;
|
||||
}
|
||||
length = 1.0 / length;
|
||||
dest.x *= length;
|
||||
dest.y *= length;
|
||||
dest.z *= length;
|
||||
dest.w *= length;
|
||||
return dest;
|
||||
}
|
||||
multiplyMat4(matrix, dest) {
|
||||
if (!dest) {
|
||||
dest = this;
|
||||
}
|
||||
return matrix.multiplyVec4(this, dest);
|
||||
}
|
||||
static mix(vector, vector2, time, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = vector.x + time * (vector2.x - vector.x);
|
||||
dest.y = vector.y + time * (vector2.y - vector.y);
|
||||
dest.z = vector.z + time * (vector2.z - vector.z);
|
||||
dest.w = vector.w + time * (vector2.w - vector.w);
|
||||
return dest;
|
||||
}
|
||||
static sum(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = vector.x + vector2.x;
|
||||
dest.y = vector.y + vector2.y;
|
||||
dest.z = vector.z + vector2.z;
|
||||
dest.w = vector.w + vector2.w;
|
||||
return dest;
|
||||
}
|
||||
static difference(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = vector.x - vector2.x;
|
||||
dest.y = vector.y - vector2.y;
|
||||
dest.z = vector.z - vector2.z;
|
||||
dest.w = vector.w - vector2.w;
|
||||
return dest;
|
||||
}
|
||||
static product(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = vector.x * vector2.x;
|
||||
dest.y = vector.y * vector2.y;
|
||||
dest.z = vector.z * vector2.z;
|
||||
dest.w = vector.w * vector2.w;
|
||||
return dest;
|
||||
}
|
||||
static quotient(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec4();
|
||||
}
|
||||
dest.x = vector.x / vector2.x;
|
||||
dest.y = vector.y / vector2.y;
|
||||
dest.z = vector.z / vector2.z;
|
||||
dest.w = vector.w / vector2.w;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
vec4.zero = new vec4([0, 0, 0, 1]);
|
||||
vec4.one = new vec4([1, 1, 1, 1]);
|
Reference in New Issue
Block a user