feat: proper sound pooling

This commit is contained in:
cha0s 2019-04-21 23:01:29 -05:00
parent 0ee3da9e63
commit 54c1009d24
2 changed files with 120 additions and 5 deletions

104
packages/sound/index.js Normal file
View File

@ -0,0 +1,104 @@
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 this();
instance.fromJSON(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() {
super();
this.interval = 0;
this.lastPlayHandle = undefined;
this.locked = false;
this.originalVolume = 1;
this.remaining = 0;
this.sound = undefined;
this.tickHandle = undefined;
}
destroy() {
clearInterval(instance.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;
}
}
}
}

View File

@ -1,7 +1,7 @@
import {Howl, Howler} from 'howler';
import {Trait} from '@avocado/entity';
import {Sound} from '..';
export class Audible extends Trait {
static defaultParams() {
@ -22,15 +22,26 @@ export class Audible extends Trait {
destroy() {
for (const key in this.sounds) {
const sound = this.sounds[key];
sound.unload();
sound.release();
}
}
loadSounds() {
for (const key in this._sounds) {
const keys = Object.keys(this._sounds);
const soundPromises = [];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const soundJSON = this._sounds[key];
this.sounds[key] = new Howl(soundJSON);
soundPromises.push(Sound.load(soundJSON.uri));
}
const soundsPromise = Promise.all(soundPromises);
soundsPromise.then((sounds) => {
for (let i = 0; i < sounds.length; i++) {
const key = keys[i];
const sound = sounds[i];
this.sounds[key] = sound;
}
});
}
methods() {