assassin-bug/framework/resonator/sources/audio-source.js

149 lines
4.5 KiB
JavaScript
Raw Permalink Normal View History

2022-11-26 01:22:02 +00:00
// 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);
}
}