Update framework stuff
parent
40425066a1
commit
ac172e4cd4
|
@ -34,6 +34,7 @@ export default class vec3 {
|
|||
multiplyByMat3(matrix: mat3, dest?: vec3): vec3;
|
||||
multiplyByQuat(quaternion: quat, dest?: vec3): vec3;
|
||||
toQuat(dest?: quat): quat;
|
||||
rotateAroundAxis(axis: vec3, angle: number): vec3;
|
||||
static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static dot(vector: vec3, vector2: vec3): number;
|
||||
static distance(vector: vec3, vector2: vec3): number;
|
||||
|
@ -45,4 +46,7 @@ export default class vec3 {
|
|||
static product(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3;
|
||||
static rotate(value: vec3, rotation: quat, dest?: vec3): vec3;
|
||||
static max(a: vec3, b: vec3): vec3;
|
||||
static min(a: vec3, b: vec3): vec3;
|
||||
static lerp(a: vec3, b: vec3, t: number): vec3;
|
||||
}
|
||||
|
|
|
@ -170,6 +170,26 @@ export default class vec3 {
|
|||
dest.w = c.x * c.y * c.z + s.x * s.y * s.z;
|
||||
return dest;
|
||||
}
|
||||
rotateAroundAxis(axis, angle) {
|
||||
const normalizedAxis = axis.normalize();
|
||||
const sinAngle = Math.sin(angle / 2);
|
||||
const cosAngle = Math.cos(angle / 2);
|
||||
// Create a quaternion representing the rotation
|
||||
const rotationQuat = new quat([
|
||||
normalizedAxis.x * sinAngle,
|
||||
normalizedAxis.y * sinAngle,
|
||||
normalizedAxis.z * sinAngle,
|
||||
cosAngle
|
||||
]);
|
||||
// Quaternion for the vector (considering the vector as a quaternion with a w value of 0)
|
||||
const vecQuat = new quat([this.x, this.y, this.z, 0]);
|
||||
// Conjugate of the rotation quaternion
|
||||
const rotationQuatConjugate = rotationQuat.conjugate();
|
||||
// Rotate the vector using quaternion multiplication: q * v * q^(-1)
|
||||
const rotatedVecQuat = rotationQuat.multiply(vecQuat).multiply(rotationQuatConjugate);
|
||||
// Return the rotated vector
|
||||
return new vec3([rotatedVecQuat.x, rotatedVecQuat.y, rotatedVecQuat.z]);
|
||||
}
|
||||
static cross(vector, vector2, dest) {
|
||||
if (!dest) {
|
||||
dest = new vec3();
|
||||
|
@ -283,6 +303,27 @@ export default class vec3 {
|
|||
dest.z = value.z + z * rotation.w + (rotation.x * y - rotation.y * x);
|
||||
return dest;
|
||||
}
|
||||
static max(a, b) {
|
||||
return new vec3([
|
||||
Math.max(a.x, b.x),
|
||||
Math.max(a.y, b.y),
|
||||
Math.max(a.z, b.z),
|
||||
]);
|
||||
}
|
||||
static min(a, b) {
|
||||
return new vec3([
|
||||
Math.min(a.x, b.x),
|
||||
Math.min(a.y, b.y),
|
||||
Math.min(a.z, b.z),
|
||||
]);
|
||||
}
|
||||
static lerp(a, b, t) {
|
||||
return new vec3([
|
||||
a.x + (b.x - a.x) * t,
|
||||
a.y + (b.y - a.y) * t,
|
||||
a.z + (b.z - a.z) * t,
|
||||
]);
|
||||
}
|
||||
}
|
||||
vec3.zero = new vec3([0, 0, 0]);
|
||||
vec3.one = new vec3([1, 1, 1]);
|
||||
|
|
|
@ -27,7 +27,12 @@ export default class ResonatorAudioContext {
|
|||
}
|
||||
decodeAudioData(data) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return yield this.context.decodeAudioData(data);
|
||||
try {
|
||||
return yield this.context.decodeAudioData(data);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
createPanner() {
|
||||
|
|
|
@ -4,8 +4,8 @@ import BaseEffect from './effects/base-effect';
|
|||
export default class AudioGraph {
|
||||
private master;
|
||||
private effectsBus;
|
||||
private worldBus;
|
||||
private secondaryBus;
|
||||
worldBus: AudioNode;
|
||||
secondaryBus: AudioNode;
|
||||
private effects;
|
||||
private scene;
|
||||
private context;
|
||||
|
|
|
@ -5,6 +5,10 @@ export default class Convolver extends BaseEffect {
|
|||
private buffer;
|
||||
private channelSplitter;
|
||||
private channelMerger;
|
||||
private outputGain;
|
||||
private volume;
|
||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
|
||||
setBuffer(buffer: AudioBuffer): void;
|
||||
setVolume(volume: number): void;
|
||||
connectInput(node: AudioNode): void;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,24 @@ import BaseEffect from './base-effect';
|
|||
export default class Convolver extends BaseEffect {
|
||||
constructor(context, graph, params) {
|
||||
super(context, graph, params);
|
||||
this.volume = 0.25;
|
||||
console.log(`Creating convolver`);
|
||||
this.effectNode = this.context.getContext().createConvolver();
|
||||
this.effectNode.normalize = true;
|
||||
this.effectNode.buffer = this.effectParams.buffer;
|
||||
}
|
||||
setBuffer(buffer) {
|
||||
this.buffer = buffer;
|
||||
if (this.effectNode) {
|
||||
this.effectNode.buffer = buffer;
|
||||
}
|
||||
}
|
||||
setVolume(volume) {
|
||||
this.volume = volume;
|
||||
if (this.outputGain) {
|
||||
this.outputGain.gain.setValueAtTime(this.volume, this.context.getContext().currentTime);
|
||||
}
|
||||
}
|
||||
connectInput(node) {
|
||||
this.channelSplitter = this.context.getContext().createChannelSplitter(2);
|
||||
this.channelMerger = this.context.getContext().createChannelMerger(2);
|
||||
|
@ -13,8 +27,11 @@ export default class Convolver extends BaseEffect {
|
|||
this.channelSplitter.connect(this.channelMerger, 1, 0);
|
||||
this.channelSplitter.connect(this.channelMerger, 0, 1);
|
||||
this.channelSplitter.connect(this.channelMerger, 1, 1);
|
||||
this.outputGain = this.context.getContext().createGain();
|
||||
this.outputGain.gain.setValueAtTime(this.volume, this.context.getContext().currentTime);
|
||||
node.connect(this.channelSplitter);
|
||||
this.channelMerger.connect(this.effectNode);
|
||||
this.channelMerger.connect(this.outputGain);
|
||||
this.outputGain.connect(this.effectNode);
|
||||
this.inputNode = node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import ResonatorScene from './scenes/webaudio-scene';
|
||||
import AudioGraph from './audio-graph';
|
||||
import AudioSource from './sources/audio-source';
|
||||
import { BaseLoader } from './loaders/base-loader';
|
||||
import { BaseSource } from './sources/base-source';
|
||||
|
@ -15,8 +17,12 @@ export default class Resonator {
|
|||
loadImmediate(path: string, type?: SourceType): AudioSource;
|
||||
stream(path: string, type?: SourceType): StreamingSource;
|
||||
private createSource;
|
||||
setEnvironmentImpulse(file: string): Promise<void>;
|
||||
setEnvironmentImpulse(file: string, volume?: number): Promise<void>;
|
||||
setEnvironmentImpulseBuffer(file: AudioBuffer, volume?: number): Promise<void>;
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
setListenerOrientation(forward: any, up: any): void;
|
||||
clearDataPool(): void;
|
||||
getAudioContext(): AudioContext;
|
||||
getAudioGraph(): AudioGraph;
|
||||
getScene(): ResonatorScene;
|
||||
}
|
||||
|
|
|
@ -51,18 +51,47 @@ export default class Resonator {
|
|||
createSource(type, data) {
|
||||
return new AudioSource(this.graph, this.scene, this.context, data);
|
||||
}
|
||||
setEnvironmentImpulse(file) {
|
||||
setEnvironmentImpulse(file, volume = 0.25) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.environmentImpulse) {
|
||||
this.graph.removeEffect(this.environmentImpulse);
|
||||
if (file === null || file === '') {
|
||||
if (this.environmentImpulse) {
|
||||
this.graph.removeEffect(this.environmentImpulse);
|
||||
this.environmentImpulse = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (file === null) {
|
||||
if (this.environmentImpulse && file !== '') {
|
||||
const buffer = yield this.dataPool.get(file);
|
||||
this.environmentImpulse.setBuffer(buffer);
|
||||
this.environmentImpulse.setVolume(volume);
|
||||
return;
|
||||
}
|
||||
const buffer = yield this.dataPool.get(file);
|
||||
this.environmentImpulse = new Convolver(this.context, this.graph, {
|
||||
buffer
|
||||
});
|
||||
this.environmentImpulse.setVolume(volume);
|
||||
this.graph.applyEffect(this.environmentImpulse);
|
||||
});
|
||||
}
|
||||
setEnvironmentImpulseBuffer(file, volume = 0.25) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (file === null) {
|
||||
if (this.environmentImpulse) {
|
||||
this.graph.removeEffect(this.environmentImpulse);
|
||||
this.environmentImpulse = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.environmentImpulse && file) {
|
||||
this.environmentImpulse.setBuffer(file);
|
||||
this.environmentImpulse.setVolume(volume);
|
||||
return;
|
||||
}
|
||||
this.environmentImpulse = new Convolver(this.context, this.graph, {
|
||||
buffer: file
|
||||
});
|
||||
this.environmentImpulse.setVolume(volume);
|
||||
this.graph.applyEffect(this.environmentImpulse);
|
||||
});
|
||||
}
|
||||
|
@ -75,4 +104,13 @@ export default class Resonator {
|
|||
clearDataPool() {
|
||||
this.dataPool.clear();
|
||||
}
|
||||
getAudioContext() {
|
||||
return this.context.getContext();
|
||||
}
|
||||
getAudioGraph() {
|
||||
return this.graph;
|
||||
}
|
||||
getScene() {
|
||||
return this.scene;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import ResonatorAudioContext from '../audio-context';
|
||||
import { EventBus } from '../../event-bus';
|
||||
import ResonatorAudioContext from "../audio-context";
|
||||
import { EventBus } from "../../event-bus";
|
||||
export default class ResonatorScene extends EventBus {
|
||||
scene: GainNode;
|
||||
context: ResonatorAudioContext;
|
||||
listener: AudioListener;
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
};
|
||||
orientation: any;
|
||||
isFirefox: boolean;
|
||||
constructor(context: ResonatorAudioContext);
|
||||
init(): void;
|
||||
createSource(): any;
|
||||
|
@ -11,4 +18,5 @@ export default class ResonatorScene extends EventBus {
|
|||
getInput(): any;
|
||||
setListenerPosition(x: number, y: number, z: number): void;
|
||||
setListenerOrientation(forward: any, rawup: any): void;
|
||||
private checkIfFirefox;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
// The code that deals with 3d audio
|
||||
import { EventBus } from '../../event-bus';
|
||||
import vec3 from '../../math/vec3';
|
||||
import { EventBus } from "../../event-bus";
|
||||
import vec3 from "../../math/vec3";
|
||||
export default class ResonatorScene extends EventBus {
|
||||
constructor(context) {
|
||||
super();
|
||||
this.position = { x: 0, y: 0, z: 0 };
|
||||
this.isFirefox = false;
|
||||
this.context = context;
|
||||
this.scene = this.context.getContext().createGain();
|
||||
this.listener = this.context.getContext().listener;
|
||||
this.position = { x: 0, y: 0, z: 0 };
|
||||
this.orientation = {
|
||||
up: { x: 0, y: 1, z: 0 },
|
||||
fwd: { x: 0, y: 0, z: -1 },
|
||||
};
|
||||
this.checkIfFirefox();
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
|
@ -14,8 +22,8 @@ export default class ResonatorScene extends EventBus {
|
|||
}
|
||||
createSource() {
|
||||
const node = this.context.getContext().createPanner();
|
||||
node.panningModel = 'HRTF';
|
||||
node.distanceModel = 'linear';
|
||||
node.panningModel = "HRTF";
|
||||
node.distanceModel = "linear";
|
||||
node.maxDistance = 20;
|
||||
node.refDistance = 2;
|
||||
node.connect(this.scene);
|
||||
|
@ -28,7 +36,17 @@ export default class ResonatorScene extends EventBus {
|
|||
return this.scene;
|
||||
}
|
||||
setListenerPosition(x, y, z) {
|
||||
this.listener.setPosition(x, y, z);
|
||||
if (x === this.position.x && y === this.position.y && z == this.position.z)
|
||||
return;
|
||||
if (this.isFirefox) {
|
||||
this.listener.setPosition(x, y, z);
|
||||
}
|
||||
else {
|
||||
this.listener.positionX.setValueAtTime(x, this.context.getContext().currentTime);
|
||||
this.listener.positionY.setValueAtTime(y, this.context.getContext().currentTime);
|
||||
this.listener.positionZ.setValueAtTime(z, this.context.getContext().currentTime);
|
||||
}
|
||||
this.position = { x, y, z };
|
||||
}
|
||||
setListenerOrientation(forward, rawup) {
|
||||
let fwd = new vec3([forward.x, forward.y, forward.z]);
|
||||
|
@ -37,6 +55,25 @@ export default class ResonatorScene extends EventBus {
|
|||
vec3.cross(up, fwd, up);
|
||||
fwd.normalize();
|
||||
up.normalize();
|
||||
this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
||||
if (fwd.x === this.orientation.fwd.x && fwd.y === this.orientation.fwd.y &&
|
||||
fwd.z === this.orientation.fwd.z && up.x === this.orientation.up.x &&
|
||||
up.y === this.orientation.up.y && up.z === this.orientation.up.z)
|
||||
return;
|
||||
// this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
||||
if (this.isFirefox) {
|
||||
this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
||||
}
|
||||
else {
|
||||
this.listener.forwardX.setValueAtTime(fwd.x, this.context.getContext().currentTime);
|
||||
this.listener.forwardY.setValueAtTime(fwd.y, this.context.getContext().currentTime);
|
||||
this.listener.forwardZ.setValueAtTime(fwd.z, this.context.getContext().currentTime);
|
||||
this.listener.upX.setValueAtTime(up.x, this.context.getContext().currentTime);
|
||||
this.listener.upY.setValueAtTime(up.y, this.context.getContext().currentTime);
|
||||
this.listener.upZ.setValueAtTime(up.z, this.context.getContext().currentTime);
|
||||
}
|
||||
this.orientation = { fwd, up };
|
||||
}
|
||||
checkIfFirefox() {
|
||||
this.isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import ResonatorAudioContext from '../audio-context';
|
|||
import AudioGraph from '../audio-graph';
|
||||
import ResonatorScene from '../scenes/webaudio-scene';
|
||||
import { BaseSource } from './base-source';
|
||||
import { DistanceModel } from './distance-model';
|
||||
import { SourceType } from './source-type';
|
||||
export default class AudioSource implements BaseSource {
|
||||
playing: boolean;
|
||||
|
@ -18,6 +19,12 @@ export default class AudioSource implements BaseSource {
|
|||
private volume;
|
||||
private gain;
|
||||
private type;
|
||||
private distanceModel;
|
||||
private maxDistance;
|
||||
private refDistance;
|
||||
private rollOffFactor;
|
||||
private filter;
|
||||
private filterFreq;
|
||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType);
|
||||
init(): void;
|
||||
getBuffer(): AudioBuffer;
|
||||
|
@ -34,4 +41,11 @@ export default class AudioSource implements BaseSource {
|
|||
loop(value: boolean): void;
|
||||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
isPlaying(): boolean;
|
||||
setDistanceModel(distanceModel: DistanceModel): void;
|
||||
setMaxDistance(distance: number): void;
|
||||
setRefDistance(ref: number): void;
|
||||
setRollOffFactor(factor: number): void;
|
||||
updateSpatialization(): void;
|
||||
setFilterFrequency(value: number): void;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import { SourceType } from './source-type';
|
||||
export default class AudioSource {
|
||||
constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) {
|
||||
this.filterFreq = 24000;
|
||||
this.position = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -19,6 +20,10 @@ export default class AudioSource {
|
|||
}
|
||||
init() {
|
||||
this.gain = this.context.createGain();
|
||||
this.filter = this.context.getContext().createBiquadFilter();
|
||||
this.filter.type = "highshelf";
|
||||
this.filter.frequency.value = this.filterFreq;
|
||||
this.filter.gain.value = -60;
|
||||
// bind methods so we can add and removve them from event listeners
|
||||
this.stop = this.stop.bind(this);
|
||||
}
|
||||
|
@ -32,12 +37,15 @@ export default class AudioSource {
|
|||
this.playOnLoad = false;
|
||||
}
|
||||
}
|
||||
play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) {
|
||||
play(when, offset, duration) {
|
||||
if (!this.context)
|
||||
return;
|
||||
if (this.playing && this.node) {
|
||||
this.stop();
|
||||
}
|
||||
if (!this.buffer) {
|
||||
this.playOnLoad = true;
|
||||
this.playing = true;
|
||||
return;
|
||||
}
|
||||
if (!this.node) {
|
||||
|
@ -47,7 +55,13 @@ export default class AudioSource {
|
|||
}
|
||||
if (this.node) {
|
||||
this.node.playbackRate.value = this.playbackRate;
|
||||
this.node.start(when, offset, duration);
|
||||
// Have to do this, otherwise when we pass duration, the node will stop before it can loop.
|
||||
if (duration) {
|
||||
this.node.start(when, offset, duration);
|
||||
}
|
||||
else {
|
||||
this.node.start(when, offset);
|
||||
}
|
||||
this.node.loop = this.looping;
|
||||
this.playing = true;
|
||||
if (this.sceneNode) {
|
||||
|
@ -57,6 +71,8 @@ export default class AudioSource {
|
|||
}
|
||||
}
|
||||
setPosition(x, y, z) {
|
||||
if (x === this.position.x && y === this.position.y && z === this.position.z)
|
||||
return;
|
||||
this.position = {
|
||||
x,
|
||||
y,
|
||||
|
@ -86,8 +102,10 @@ export default class AudioSource {
|
|||
case SourceType.WorldSource:
|
||||
if (!this.sceneNode) {
|
||||
this.sceneNode = this.scene.createSource();
|
||||
this.updateSpatialization();
|
||||
}
|
||||
this.node.connect(this.gain);
|
||||
this.node.connect(this.filter);
|
||||
this.filter.connect(this.gain);
|
||||
this.gain.connect(this.sceneNode);
|
||||
break;
|
||||
case SourceType.UISource:
|
||||
|
@ -145,4 +163,41 @@ export default class AudioSource {
|
|||
}
|
||||
this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time);
|
||||
}
|
||||
isPlaying() {
|
||||
return this.playing;
|
||||
}
|
||||
setDistanceModel(distanceModel) {
|
||||
this.distanceModel = distanceModel;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setMaxDistance(distance) {
|
||||
this.maxDistance = this.maxDistance;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setRefDistance(ref) {
|
||||
this.refDistance = ref;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setRollOffFactor(factor) {
|
||||
this.rollOffFactor = factor;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
updateSpatialization() {
|
||||
if (this.sceneNode) {
|
||||
if (this.distanceModel)
|
||||
this.sceneNode.distanceModel = this.distanceModel;
|
||||
if (this.refDistance)
|
||||
this.sceneNode.refDistance = this.refDistance;
|
||||
if (this.rollOffFactor)
|
||||
this.sceneNode.rolloffFactor = this.rollOffFactor;
|
||||
if (this.maxDistance)
|
||||
this.sceneNode.maxDistance = this.maxDistance;
|
||||
}
|
||||
}
|
||||
setFilterFrequency(value) {
|
||||
this.filterFreq = value;
|
||||
if (this.filter) {
|
||||
this.filter.frequency.value = this.filterFreq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,5 @@ export interface BaseSource {
|
|||
fadeOut(time: number): void;
|
||||
fadeIn(time: number): void;
|
||||
destroy(): void;
|
||||
isPlaying(): boolean;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export declare enum DistanceModel {
|
||||
linear = "linear",
|
||||
inverse = "inverse",
|
||||
exponential = "exponential"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export var DistanceModel;
|
||||
(function (DistanceModel) {
|
||||
DistanceModel["linear"] = "linear";
|
||||
DistanceModel["inverse"] = "inverse";
|
||||
DistanceModel["exponential"] = "exponential";
|
||||
})(DistanceModel || (DistanceModel = {}));
|
|
@ -3,6 +3,7 @@ import AudioGraph from '../audio-graph';
|
|||
import ResonatorScene from '../scenes/webaudio-scene';
|
||||
import ResonatorAudioContext from '../audio-context';
|
||||
import { SourceType } from './source-type';
|
||||
import { DistanceModel } from './distance-model';
|
||||
export declare class StreamingSource implements BaseSource {
|
||||
private graph;
|
||||
private scene;
|
||||
|
@ -16,6 +17,12 @@ export declare class StreamingSource implements BaseSource {
|
|||
private sceneNode;
|
||||
private gain;
|
||||
private position;
|
||||
private distanceModel;
|
||||
private maxDistance;
|
||||
private refDistance;
|
||||
private rollOffFactor;
|
||||
private filter;
|
||||
private filterFreq;
|
||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType);
|
||||
private init;
|
||||
play(when?: number, offset?: number, duration?: number): void;
|
||||
|
@ -30,4 +37,11 @@ export declare class StreamingSource implements BaseSource {
|
|||
loop(value: boolean): void;
|
||||
fadeIn(time: number): void;
|
||||
fadeOut(time: number): void;
|
||||
isPlaying(): boolean;
|
||||
setDistanceModel(distanceModel: DistanceModel): void;
|
||||
setMaxDistance(distance: number): void;
|
||||
setRefDistance(ref: number): void;
|
||||
setRollOffFactor(factor: number): void;
|
||||
updateSpatialization(): void;
|
||||
setFilterFrequency(value: number): void;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ export class StreamingSource {
|
|||
this.context = context;
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
this.filterFreq = 24000;
|
||||
this.position = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -15,6 +16,10 @@ export class StreamingSource {
|
|||
}
|
||||
init() {
|
||||
this.node = this.context.createMediaElementSource(this.element);
|
||||
this.filter = this.context.getContext().createBiquadFilter();
|
||||
this.filter.type = "lowshelf";
|
||||
this.filter.gain.value = -60;
|
||||
this.filter.frequency.value = this.filterFreq;
|
||||
this.gain = this.context.createGain();
|
||||
this.createConnections();
|
||||
this.element.addEventListener('canplay', (event) => {
|
||||
|
@ -50,8 +55,10 @@ export class StreamingSource {
|
|||
case SourceType.WorldSource:
|
||||
if (!this.sceneNode) {
|
||||
this.sceneNode = this.scene.createSource();
|
||||
this.updateSpatialization();
|
||||
}
|
||||
this.node.connect(this.gain);
|
||||
this.node.connect(this.filter);
|
||||
this.filter.connect(this.gain);
|
||||
this.gain.connect(this.sceneNode);
|
||||
break;
|
||||
default:
|
||||
|
@ -96,4 +103,37 @@ export class StreamingSource {
|
|||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
||||
setTimeout(() => this.stop(), time * 1000);
|
||||
}
|
||||
isPlaying() {
|
||||
return this.playing;
|
||||
}
|
||||
setDistanceModel(distanceModel) {
|
||||
this.distanceModel = distanceModel;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setMaxDistance(distance) {
|
||||
this.maxDistance = this.maxDistance;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setRefDistance(ref) {
|
||||
this.refDistance = ref;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
setRollOffFactor(factor) {
|
||||
this.rollOffFactor = factor;
|
||||
this.updateSpatialization();
|
||||
}
|
||||
updateSpatialization() {
|
||||
if (this.sceneNode) {
|
||||
this.sceneNode.distanceModel = this.distanceModel;
|
||||
this.sceneNode.refDistance = this.refDistance;
|
||||
this.sceneNode.rolloffFactor = this.rollOffFactor;
|
||||
this.sceneNode.maxDistance = this.maxDistance;
|
||||
}
|
||||
}
|
||||
setFilterFrequency(value) {
|
||||
this.filterFreq = value;
|
||||
if (this.filter) {
|
||||
this.filter.frequency.value = this.filterFreq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { SchedulerNode } from './node';
|
||||
export declare class RAFTimer {
|
||||
isStarted: boolean;
|
||||
private lastTime;
|
||||
private currTime;
|
||||
node: SchedulerNode;
|
||||
constructor(node: SchedulerNode);
|
||||
start(): void;
|
||||
stop(): void;
|
||||
schedule(): void;
|
||||
handleResolve(): void;
|
||||
handleResolve(dt: number): void;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export class RAFTimer {
|
||||
constructor(node) {
|
||||
this.lastTime = 0;
|
||||
this.currTime = 0;
|
||||
this.isStarted = false;
|
||||
this.node = node;
|
||||
}
|
||||
|
@ -13,9 +15,17 @@ export class RAFTimer {
|
|||
schedule() {
|
||||
window.requestAnimationFrame(this.handleResolve.bind(this));
|
||||
}
|
||||
handleResolve() {
|
||||
handleResolve(dt) {
|
||||
if (this.node) {
|
||||
this.node.func(1);
|
||||
if (!this.lastTime) {
|
||||
this.lastTime = dt;
|
||||
this.node.func(1);
|
||||
}
|
||||
else {
|
||||
const delta = dt - this.lastTime;
|
||||
this.lastTime = dt;
|
||||
this.node.func(delta / 1000);
|
||||
}
|
||||
if (this.isStarted) {
|
||||
this.schedule();
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ export declare class Timer {
|
|||
start(): void;
|
||||
stop(): void;
|
||||
schedule(): void;
|
||||
handleResolve(): void;
|
||||
handleResolve(dt: number): void;
|
||||
}
|
||||
|
|
|
@ -3,34 +3,30 @@ export class Timer {
|
|||
this.time = time;
|
||||
this.node = node;
|
||||
this.isStarted = false;
|
||||
this.fluctuation = 0;
|
||||
}
|
||||
start() {
|
||||
this.isStarted = true;
|
||||
this.lastTime = performance.now();
|
||||
this.schedule();
|
||||
}
|
||||
stop() {
|
||||
if (this.isStarted) {
|
||||
if (this.intervalID) {
|
||||
clearTimeout(this.intervalID);
|
||||
this.intervalID = null;
|
||||
this.isStarted = false;
|
||||
}
|
||||
clearTimeout(this.intervalID);
|
||||
this.isStarted = false;
|
||||
}
|
||||
}
|
||||
schedule() {
|
||||
let toWait = this.time;
|
||||
if (this.lastTime) {
|
||||
const fluc = Date.now() - this.lastTime;
|
||||
this.fluctuation = fluc;
|
||||
toWait -= fluc;
|
||||
}
|
||||
this.lastTime = Date.now();
|
||||
this.intervalID = setTimeout(this.handleResolve.bind(this), toWait);
|
||||
const now = performance.now();
|
||||
const elapsed = now - this.lastTime;
|
||||
this.fluctuation = elapsed - this.time;
|
||||
this.lastTime = now;
|
||||
const toWait = Math.max(0, this.time - this.fluctuation);
|
||||
this.intervalID = window.setTimeout(() => this.handleResolve(elapsed), toWait);
|
||||
}
|
||||
handleResolve() {
|
||||
this.lastTime = Date.now();
|
||||
handleResolve(dt) {
|
||||
if (this.node) {
|
||||
this.node.func(this.time / this.lastTime);
|
||||
this.node.func(dt / 1000); // Assuming time is in milliseconds
|
||||
}
|
||||
if (this.isStarted) {
|
||||
this.schedule();
|
||||
|
|
Loading…
Reference in New Issue