UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

208 lines 6.59 kB
import { Observable } from "../../Misc/observable.js"; import { AbstractNamedAudioNode } from "./abstractAudioNode.js"; import { _GetVolumeAudioProperty, _GetVolumeAudioSubNode } from "./subNodes/volumeAudioSubNode.js"; import { _AudioAnalyzer } from "./subProperties/audioAnalyzer.js"; /** * Abstract class representing a sound in the audio engine. */ export class AbstractSound extends AbstractNamedAudioNode { constructor(name, engine) { super(name, engine, 3 /* AudioNodeType.HAS_INPUTS_AND_OUTPUTS */); // Inputs are for instances. this._analyzer = null; this._newestInstance = null; this._outBus = null; this._privateInstances = new Set(); this._state = 1 /* SoundState.Stopped */; this._instances = this._privateInstances; /** * Observable for when the sound stops playing. */ this.onEndedObservable = new Observable(); this._onInstanceEnded = (instance) => { if (this._newestInstance === instance) { this._newestInstance = null; } this._privateInstances.delete(instance); if (this._instances.size === 0) { this._state = 1 /* SoundState.Stopped */; this.onEndedObservable.notifyObservers(this); } }; this._onOutBusDisposed = () => { this._outBus = null; }; } /** * The analyzer features of the sound. */ get analyzer() { return this._analyzer ?? (this._analyzer = new _AudioAnalyzer(this._subGraph)); } /** * Whether the sound should start playing automatically. Defaults to `false`. */ get autoplay() { return this._options.autoplay; } /** * The current playback time of the sound, in seconds. */ get currentTime() { const instance = this._getNewestInstance(); return instance ? instance.currentTime : 0; } set currentTime(value) { this.startOffset = value; const instance = this._getNewestInstance(); if (instance) { instance.currentTime = value; } } /** * Whether the sound should loop. Defaults to `false`. */ get loop() { return this._options.loop; } set loop(value) { this._options.loop = value; } /** * The maximum number of instances that can play at the same time. Defaults to `Infinity`. */ get maxInstances() { return this._options.maxInstances; } set maxInstances(value) { this._options.maxInstances = value; } /** * The output bus for the sound. Defaults to `null`. * - If not set or `null`, the sound is automatically connected to the audio engine's default main bus. * @see {@link AudioEngineV2.defaultMainBus} */ get outBus() { return this._outBus; } set outBus(outBus) { if (this._outBus === outBus) { return; } if (this._outBus) { this._outBus.onDisposeObservable.removeCallback(this._onOutBusDisposed); if (!this._disconnect(this._outBus)) { throw new Error("Disconnect failed"); } } this._outBus = outBus; if (this._outBus) { this._outBus.onDisposeObservable.add(this._onOutBusDisposed); if (!this._connect(this._outBus)) { throw new Error("Connect failed"); } } } /** * The time within the sound buffer to start playing at, in seconds. Defaults to `0`. */ get startOffset() { return this._options.startOffset; } set startOffset(value) { this._options.startOffset = value; } /** * The state of the sound. */ get state() { return this._state; } /** * The output volume of the sound. */ get volume() { return _GetVolumeAudioProperty(this._subGraph, "volume"); } set volume(value) { // The volume subnode is created on initialization and should always exist. const node = _GetVolumeAudioSubNode(this._subGraph); if (!node) { throw new Error("No volume subnode"); } node.volume = value; } /** * Releases associated resources. */ dispose() { super.dispose(); this.stop(); this._analyzer?.dispose(); this._analyzer = null; this._newestInstance = null; this._outBus = null; this._privateInstances.clear(); this.onEndedObservable.clear(); } /** * Pauses the sound. */ pause() { const it = this._instances.values(); for (let next = it.next(); !next.done; next = it.next()) { next.value.pause(); } this._state = 5 /* SoundState.Paused */; } /** * Resumes the sound. */ resume() { if (this._state !== 5 /* SoundState.Paused */) { return; } const it = this._instances.values(); for (let next = it.next(); !next.done; next = it.next()) { next.value.resume(); } this._state = 3 /* SoundState.Started */; } _beforePlay(instance) { if (this.state === 5 /* SoundState.Paused */ && this._instances.size > 0) { this.resume(); return; } instance.onEndedObservable.addOnce(this._onInstanceEnded); this._privateInstances.add(instance); this._newestInstance = instance; } _afterPlay(instance) { this._state = instance.state; } _getNewestInstance() { if (this._instances.size === 0) { return null; } if (!this._newestInstance) { const it = this._instances.values(); for (let next = it.next(); !next.done; next = it.next()) { this._newestInstance = next.value; } } return this._newestInstance; } _setState(state) { this._state = state; } _stopExcessInstances() { if (this.maxInstances < Infinity) { const numberOfInstancesToStop = Array.from(this._instances).filter((instance) => instance.state === 3 /* SoundState.Started */).length - this.maxInstances; const it = this._instances.values(); for (let i = 0; i < numberOfInstancesToStop; i++) { const instance = it.next().value; instance.stop(); } } } } //# sourceMappingURL=abstractSound.js.map