123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- import { Sound } from "./sound.js";
- import { SoundTrack } from "./soundTrack.js";
- import { Engine } from "../Engines/engine.js";
- import { Matrix, Vector3 } from "../Maths/math.vector.js";
- import { SceneComponentConstants } from "../sceneComponent.js";
- import { Scene } from "../scene.js";
- import { AbstractScene } from "../abstractScene.js";
- import "./audioEngine.js";
- import { PrecisionDate } from "../Misc/precisionDate.js";
- import { EngineStore } from "../Engines/engineStore.js";
- // Adds the parser to the scene parsers.
- AbstractScene.AddParser(SceneComponentConstants.NAME_AUDIO, (parsedData, scene, container, rootUrl) => {
- // TODO: add sound
- let loadedSounds = [];
- let loadedSound;
- container.sounds = container.sounds || [];
- if (parsedData.sounds !== undefined && parsedData.sounds !== null) {
- for (let index = 0, cache = parsedData.sounds.length; index < cache; index++) {
- const parsedSound = parsedData.sounds[index];
- if (Engine.audioEngine?.canUseWebAudio) {
- if (!parsedSound.url) {
- parsedSound.url = parsedSound.name;
- }
- if (!loadedSounds[parsedSound.url]) {
- loadedSound = Sound.Parse(parsedSound, scene, rootUrl);
- loadedSounds[parsedSound.url] = loadedSound;
- container.sounds.push(loadedSound);
- }
- else {
- container.sounds.push(Sound.Parse(parsedSound, scene, rootUrl, loadedSounds[parsedSound.url]));
- }
- }
- else {
- container.sounds.push(new Sound(parsedSound.name, null, scene));
- }
- }
- }
- loadedSounds = [];
- });
- Object.defineProperty(Scene.prototype, "mainSoundTrack", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- if (!this._mainSoundTrack) {
- this._mainSoundTrack = new SoundTrack(this, { mainTrack: true });
- }
- return this._mainSoundTrack;
- },
- enumerable: true,
- configurable: true,
- });
- Scene.prototype.getSoundByName = function (name) {
- let index;
- for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) {
- if (this.mainSoundTrack.soundCollection[index].name === name) {
- return this.mainSoundTrack.soundCollection[index];
- }
- }
- if (this.soundTracks) {
- for (let sdIndex = 0; sdIndex < this.soundTracks.length; sdIndex++) {
- for (index = 0; index < this.soundTracks[sdIndex].soundCollection.length; index++) {
- if (this.soundTracks[sdIndex].soundCollection[index].name === name) {
- return this.soundTracks[sdIndex].soundCollection[index];
- }
- }
- }
- }
- return null;
- };
- Object.defineProperty(Scene.prototype, "audioEnabled", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- return compo.audioEnabled;
- },
- set: function (value) {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- if (value) {
- compo.enableAudio();
- }
- else {
- compo.disableAudio();
- }
- },
- enumerable: true,
- configurable: true,
- });
- Object.defineProperty(Scene.prototype, "headphone", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- return compo.headphone;
- },
- set: function (value) {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- if (value) {
- compo.switchAudioModeForHeadphones();
- }
- else {
- compo.switchAudioModeForNormalSpeakers();
- }
- },
- enumerable: true,
- configurable: true,
- });
- Object.defineProperty(Scene.prototype, "audioListenerPositionProvider", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- return compo.audioListenerPositionProvider;
- },
- set: function (value) {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- if (value && typeof value !== "function") {
- throw new Error("The value passed to [Scene.audioListenerPositionProvider] must be a function that returns a Vector3");
- }
- else {
- compo.audioListenerPositionProvider = value;
- }
- },
- enumerable: true,
- configurable: true,
- });
- Object.defineProperty(Scene.prototype, "audioListenerRotationProvider", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- return compo.audioListenerRotationProvider;
- },
- set: function (value) {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- if (value && typeof value !== "function") {
- throw new Error("The value passed to [Scene.audioListenerRotationProvider] must be a function that returns a Vector3");
- }
- else {
- compo.audioListenerRotationProvider = value;
- }
- },
- enumerable: true,
- configurable: true,
- });
- Object.defineProperty(Scene.prototype, "audioPositioningRefreshRate", {
- get: function () {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- return compo.audioPositioningRefreshRate;
- },
- set: function (value) {
- let compo = this._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(this);
- this._addComponent(compo);
- }
- compo.audioPositioningRefreshRate = value;
- },
- enumerable: true,
- configurable: true,
- });
- /**
- * Defines the sound scene component responsible to manage any sounds
- * in a given scene.
- */
- export class AudioSceneComponent {
- /**
- * Gets whether audio is enabled or not.
- * Please use related enable/disable method to switch state.
- */
- get audioEnabled() {
- return this._audioEnabled;
- }
- /**
- * Gets whether audio is outputting to headphone or not.
- * Please use the according Switch methods to change output.
- */
- get headphone() {
- return this._headphone;
- }
- /**
- * Creates a new instance of the component for the given scene
- * @param scene Defines the scene to register the component in
- */
- constructor(scene) {
- /**
- * The component name helpful to identify the component in the list of scene components.
- */
- this.name = SceneComponentConstants.NAME_AUDIO;
- this._audioEnabled = true;
- this._headphone = false;
- /**
- * Gets or sets a refresh rate when using 3D audio positioning
- */
- this.audioPositioningRefreshRate = 500;
- /**
- * Gets or Sets a custom listener position for all sounds in the scene
- * By default, this is the position of the first active camera
- */
- this.audioListenerPositionProvider = null;
- /**
- * Gets or Sets a custom listener rotation for all sounds in the scene
- * By default, this is the rotation of the first active camera
- */
- this.audioListenerRotationProvider = null;
- this._cachedCameraDirection = new Vector3();
- this._cachedCameraPosition = new Vector3();
- this._lastCheck = 0;
- this._invertMatrixTemp = new Matrix();
- this._cameraDirectionTemp = new Vector3();
- scene = scene || EngineStore.LastCreatedScene;
- if (!scene) {
- return;
- }
- this.scene = scene;
- scene.soundTracks = [];
- scene.sounds = [];
- }
- /**
- * Registers the component in a given scene
- */
- register() {
- this.scene._afterRenderStage.registerStep(SceneComponentConstants.STEP_AFTERRENDER_AUDIO, this, this._afterRender);
- }
- /**
- * Rebuilds the elements related to this component in case of
- * context lost for instance.
- */
- rebuild() {
- // Nothing to do here. (Not rendering related)
- }
- /**
- * Serializes the component data to the specified json object
- * @param serializationObject The object to serialize to
- */
- serialize(serializationObject) {
- serializationObject.sounds = [];
- if (this.scene.soundTracks) {
- for (let index = 0; index < this.scene.soundTracks.length; index++) {
- const soundtrack = this.scene.soundTracks[index];
- for (let soundId = 0; soundId < soundtrack.soundCollection.length; soundId++) {
- serializationObject.sounds.push(soundtrack.soundCollection[soundId].serialize());
- }
- }
- }
- }
- /**
- * Adds all the elements from the container to the scene
- * @param container the container holding the elements
- */
- addFromContainer(container) {
- if (!container.sounds) {
- return;
- }
- container.sounds.forEach((sound) => {
- sound.play();
- sound.autoplay = true;
- this.scene.mainSoundTrack.addSound(sound);
- });
- }
- /**
- * Removes all the elements in the container from the scene
- * @param container contains the elements to remove
- * @param dispose if the removed element should be disposed (default: false)
- */
- removeFromContainer(container, dispose = false) {
- if (!container.sounds) {
- return;
- }
- container.sounds.forEach((sound) => {
- sound.stop();
- sound.autoplay = false;
- this.scene.mainSoundTrack.removeSound(sound);
- if (dispose) {
- sound.dispose();
- }
- });
- }
- /**
- * Disposes the component and the associated resources.
- */
- dispose() {
- const scene = this.scene;
- if (scene._mainSoundTrack) {
- scene.mainSoundTrack.dispose();
- }
- if (scene.soundTracks) {
- for (let scIndex = 0; scIndex < scene.soundTracks.length; scIndex++) {
- scene.soundTracks[scIndex].dispose();
- }
- }
- }
- /**
- * Disables audio in the associated scene.
- */
- disableAudio() {
- const scene = this.scene;
- this._audioEnabled = false;
- if (Engine.audioEngine && Engine.audioEngine.audioContext) {
- Engine.audioEngine.audioContext.suspend();
- }
- let i;
- for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
- scene.mainSoundTrack.soundCollection[i].pause();
- }
- if (scene.soundTracks) {
- for (i = 0; i < scene.soundTracks.length; i++) {
- for (let j = 0; j < scene.soundTracks[i].soundCollection.length; j++) {
- scene.soundTracks[i].soundCollection[j].pause();
- }
- }
- }
- }
- /**
- * Enables audio in the associated scene.
- */
- enableAudio() {
- const scene = this.scene;
- this._audioEnabled = true;
- if (Engine.audioEngine && Engine.audioEngine.audioContext) {
- Engine.audioEngine.audioContext.resume();
- }
- let i;
- for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
- if (scene.mainSoundTrack.soundCollection[i].isPaused) {
- scene.mainSoundTrack.soundCollection[i].play();
- }
- }
- if (scene.soundTracks) {
- for (i = 0; i < scene.soundTracks.length; i++) {
- for (let j = 0; j < scene.soundTracks[i].soundCollection.length; j++) {
- if (scene.soundTracks[i].soundCollection[j].isPaused) {
- scene.soundTracks[i].soundCollection[j].play();
- }
- }
- }
- }
- }
- /**
- * Switch audio to headphone output.
- */
- switchAudioModeForHeadphones() {
- const scene = this.scene;
- this._headphone = true;
- scene.mainSoundTrack.switchPanningModelToHRTF();
- if (scene.soundTracks) {
- for (let i = 0; i < scene.soundTracks.length; i++) {
- scene.soundTracks[i].switchPanningModelToHRTF();
- }
- }
- }
- /**
- * Switch audio to normal speakers.
- */
- switchAudioModeForNormalSpeakers() {
- const scene = this.scene;
- this._headphone = false;
- scene.mainSoundTrack.switchPanningModelToEqualPower();
- if (scene.soundTracks) {
- for (let i = 0; i < scene.soundTracks.length; i++) {
- scene.soundTracks[i].switchPanningModelToEqualPower();
- }
- }
- }
- _afterRender() {
- const now = PrecisionDate.Now;
- if (this._lastCheck && now - this._lastCheck < this.audioPositioningRefreshRate) {
- return;
- }
- this._lastCheck = now;
- const scene = this.scene;
- if (!this._audioEnabled || !scene._mainSoundTrack || !scene.soundTracks || (scene._mainSoundTrack.soundCollection.length === 0 && scene.soundTracks.length === 1)) {
- return;
- }
- const audioEngine = Engine.audioEngine;
- if (!audioEngine) {
- return;
- }
- if (audioEngine.audioContext) {
- let listeningCamera = scene.activeCamera;
- if (scene.activeCameras && scene.activeCameras.length > 0) {
- listeningCamera = scene.activeCameras[0];
- }
- // A custom listener position provider was set
- // Use the users provided position instead of camera's
- if (this.audioListenerPositionProvider) {
- const position = this.audioListenerPositionProvider();
- // Set the listener position
- audioEngine.audioContext.listener.setPosition(position.x || 0, position.y || 0, position.z || 0);
- // Check if there is a listening camera
- }
- else if (listeningCamera) {
- // Set the listener position to the listening camera global position
- if (!this._cachedCameraPosition.equals(listeningCamera.globalPosition)) {
- this._cachedCameraPosition.copyFrom(listeningCamera.globalPosition);
- audioEngine.audioContext.listener.setPosition(listeningCamera.globalPosition.x, listeningCamera.globalPosition.y, listeningCamera.globalPosition.z);
- }
- }
- // Otherwise set the listener position to 0, 0 ,0
- else {
- // Set the listener position
- audioEngine.audioContext.listener.setPosition(0, 0, 0);
- }
- // A custom listener rotation provider was set
- // Use the users provided rotation instead of camera's
- if (this.audioListenerRotationProvider) {
- const rotation = this.audioListenerRotationProvider();
- audioEngine.audioContext.listener.setOrientation(rotation.x || 0, rotation.y || 0, rotation.z || 0, 0, 1, 0);
- // Check if there is a listening camera
- }
- else if (listeningCamera) {
- // for VR cameras
- if (listeningCamera.rigCameras && listeningCamera.rigCameras.length > 0) {
- listeningCamera = listeningCamera.rigCameras[0];
- }
- listeningCamera.getViewMatrix().invertToRef(this._invertMatrixTemp);
- Vector3.TransformNormalToRef(AudioSceneComponent._CameraDirection, this._invertMatrixTemp, this._cameraDirectionTemp);
- this._cameraDirectionTemp.normalize();
- // To avoid some errors on GearVR
- if (!isNaN(this._cameraDirectionTemp.x) && !isNaN(this._cameraDirectionTemp.y) && !isNaN(this._cameraDirectionTemp.z)) {
- if (!this._cachedCameraDirection.equals(this._cameraDirectionTemp)) {
- this._cachedCameraDirection.copyFrom(this._cameraDirectionTemp);
- audioEngine.audioContext.listener.setOrientation(this._cameraDirectionTemp.x, this._cameraDirectionTemp.y, this._cameraDirectionTemp.z, 0, 1, 0);
- }
- }
- }
- // Otherwise set the listener rotation to 0, 0 ,0
- else {
- // Set the listener position
- audioEngine.audioContext.listener.setOrientation(0, 0, 0, 0, 1, 0);
- }
- let i;
- for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
- const sound = scene.mainSoundTrack.soundCollection[i];
- if (sound.useCustomAttenuation) {
- sound.updateDistanceFromListener();
- }
- }
- if (scene.soundTracks) {
- for (i = 0; i < scene.soundTracks.length; i++) {
- for (let j = 0; j < scene.soundTracks[i].soundCollection.length; j++) {
- const sound = scene.soundTracks[i].soundCollection[j];
- if (sound.useCustomAttenuation) {
- sound.updateDistanceFromListener();
- }
- }
- }
- }
- }
- }
- }
- AudioSceneComponent._CameraDirection = new Vector3(0, 0, -1);
- Sound._SceneComponentInitialization = (scene) => {
- let compo = scene._getComponent(SceneComponentConstants.NAME_AUDIO);
- if (!compo) {
- compo = new AudioSceneComponent(scene);
- scene._addComponent(compo);
- }
- };
- //# sourceMappingURL=audioSceneComponent.js.map
|