Home Reference Source

js/game/sound_proxy.js

/* typehints:start */
import { GameRoot } from "./root";
/* typehints:end */

import { Vector } from "../core/vector";
import { SOUNDS } from "../platform/sound";

const avgSoundDurationSeconds = 0.1;
const maxOngoingSounds = 2;
const maxOngoingUiSounds = 5;

// Proxy to the application sound instance
export class SoundProxy {
    /**
     * @param {GameRoot} root
     */
    constructor(root) {
        this.root = root;

        // Store a list of sounds and when we started them
        this.playing3DSounds = [];
        this.playingUiSounds = [];
    }

    /**
     * Plays a new ui sound
     * @param {string} id Sound ID
     */
    playUi(id) {
        assert(typeof id === "string", "Not a valid sound id: " + id);
        this.internalUpdateOngoingSounds();
        if (this.playingUiSounds.length > maxOngoingUiSounds) {
            // Too many ongoing sounds
            return false;
        }

        this.root.app.sound.playUiSound(id);
        this.playingUiSounds.push(this.root.time.realtimeNow());
    }

    /**
     * Plays the ui click sound
     */
    playUiClick() {
        this.playUi(SOUNDS.uiClick);
    }

    /**
     * Plays the ui error sound
     */
    playUiError() {
        this.playUi(SOUNDS.uiError);
    }

    /**
     * Plays a 3D sound whose volume is scaled based on where it was emitted
     * @param {string} id Sound ID
     * @param {Vector} pos World space position
     */
    play3D(id, pos) {
        assert(typeof id === "string", "Not a valid sound id: " + id);
        assert(pos instanceof Vector, "Invalid sound position");
        this.internalUpdateOngoingSounds();

        if (this.playing3DSounds.length > maxOngoingSounds) {
            // Too many ongoing sounds
            return false;
        }

        this.root.app.sound.play3DSound(id, pos, this.root);
        this.playing3DSounds.push(this.root.time.realtimeNow());
        return true;
    }

    /**
     * Updates the list of ongoing sounds
     */
    internalUpdateOngoingSounds() {
        const now = this.root.time.realtimeNow();
        for (let i = 0; i < this.playing3DSounds.length; ++i) {
            if (now - this.playing3DSounds[i] > avgSoundDurationSeconds) {
                this.playing3DSounds.splice(i, 1);
                i -= 1;
            }
        }

        for (let i = 0; i < this.playingUiSounds.length; ++i) {
            if (now - this.playingUiSounds[i] > avgSoundDurationSeconds) {
                this.playingUiSounds.splice(i, 1);
                i -= 1;
            }
        }
    }
}