avocado-old/packages/sound/sound.js
2019-11-03 10:40:52 -06:00

107 lines
2.3 KiB
JavaScript

import {Howl, Howler} from 'howler';
import {Resource} from '@avocado/resource';
export class Sound extends Resource {
static load(uri) {
if (!this.loadCache) {
this.loadCache = {};
}
if (!this.refCache) {
this.refCache = {};
}
if (!(uri in this.refCache)) {
this.refCache[uri] = 0;
}
this.refCache[uri] += 1;
if (this.loadCache[uri]) {
return this.loadCache[uri];
}
return this.loadCache[uri] = this.read(uri).then((json) => {
const instance = new Sound(json);
let lastTime = performance.now();
instance.tickHandle = setInterval(() => {
const now = performance.now();
const elapsed = (now - lastTime) / 1000;
lastTime = now;
instance.tick(elapsed);
}, 20);
return new Promise((resolve) => {
instance.sound.once('load', () => {
resolve(instance);
});
});
});
}
constructor(json) {
super();
this.interval = 0;
this.lastPlayHandle = undefined;
this.locked = false;
this.originalVolume = 1;
this.remaining = 0;
this.sound = undefined;
this.tickHandle = undefined;
if ('undefined' !== typeof json) {
this.fromJSON(json);
}
}
destroy() {
clearInterval(this.tickHandle);
if (this.sound) {
this.sound.unload();
}
}
fromJSON(json) {
super.fromJSON(json);
if (json.interval) {
this.interval = json.interval;
}
if (json.volume) {
this.originalVolume = json.volume;
}
this.sound = new Howl(json);
return this;
}
play() {
if (this.locked) {
const volume = this.sound.volume(this.lastPlayHandle);
this.sound.volume(
Math.min(1, Math.min(volume, this.originalVolume * 20)),
this.lastPlayHandle
);
return;
}
this.lastPlayHandle = this.sound.play();
if (this.interval > 0) {
this.locked = true;
this.remaining = this.interval;
}
}
release() {
const ctor = this.constructor;
const uri = this.uri;
ctor.refCache[uri] -= 1;
if (0 === ctor.refCache[uri]) {
delete ctor.loadCache[uri];
this.destroy();
}
}
tick(elapsed) {
if (this.locked && this.interval > 0) {
this.remaining -= elapsed;
if (this.remaining <= 0) {
this.locked = false;
}
}
}
}