107 lines
2.3 KiB
JavaScript
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|