浏览代码

Move sounds to component

sebastien 7 年之前
父节点
当前提交
f7d0fd084f

+ 3 - 1
Tools/Gulp/config.json

@@ -586,7 +586,9 @@
                 "../../src/Audio/babylon.sound.js",
                 "../../src/Audio/babylon.soundtrack.js",
                 "../../src/Audio/babylon.analyser.js",
-                "../../src/Audio/babylon.weightedsound.js"
+                "../../src/Audio/babylon.weightedsound.js",
+                "../../src/Audio/babylon.audioSceneComponent.js",
+                "../../src/Actions/babylon.directAudioActions.js"
             ],
             "dependUpon": [
                 "core"

+ 6 - 2
src/Actions/babylon.actionManager.ts

@@ -677,8 +677,12 @@
                                 value = target = scene.getNodeByName(value);
                         else if (name === "parent")
                             value = scene.getNodeByName(value);
-                        else if (name === "sound")
-                            value = scene.getSoundByName(value);
+                        else if (name === "sound") {
+                            // Can not externalize to component, so only checks for the presence off the API.
+                            if (scene.getSoundByName) {
+                                value = scene.getSoundByName(value);
+                            }
+                        }
                         else if (name !== "propertyPath") {
                             if (parsedAction.type === 2 && name === "operator")
                                 value = (<any>ValueCondition)[value];

+ 0 - 50
src/Actions/babylon.directActions.ts

@@ -281,54 +281,4 @@
             }, parent);
         }
     }
-
-    export class PlaySoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        /** @hidden */
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.play();
-        }
-
-        public serialize(parent: any): any {
-            return super._serialize({
-                name: "PlaySoundAction",
-                properties: [{ name: "sound", value: this._sound.name }]
-            }, parent);
-        }
-    }
-
-    export class StopSoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        /** @hidden */
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.stop();
-        }
-
-        public serialize(parent: any): any {
-            return super._serialize({
-                name: "StopSoundAction",
-                properties: [{ name: "sound", value: this._sound.name }]
-            }, parent);
-        }
-    }
 } 

+ 85 - 0
src/Actions/babylon.directAudioActions.ts

@@ -0,0 +1,85 @@
+module BABYLON {
+    /**
+     * This defines an action helpful to play a defined sound on a triggered action.
+     */
+    export class PlaySoundAction extends Action {
+        private _sound: Sound;
+
+        /**
+         * Instantiate the action
+         * @param triggerOptions defines the trigger options
+         * @param sound defines the sound to play
+         * @param condition defines the trigger related conditions
+         */
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        /** @hidden */
+        public _prepare(): void {
+        }
+
+        /**
+         * Execute the action and play the sound.
+         */
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.play();
+        }
+
+        /**
+         * Serializes the actions and its related information.
+         * @param parent defines the object to serialize in
+         * @returns the serialized object
+         */
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "PlaySoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        }
+    }
+
+    /**
+     * This defines an action helpful to stop a defined sound on a triggered action.
+     */
+    export class StopSoundAction extends Action {
+        private _sound: Sound;
+
+        /**
+         * Instantiate the action
+         * @param triggerOptions defines the trigger options
+         * @param sound defines the sound to stop
+         * @param condition defines the trigger related conditions
+         */
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        /** @hidden */
+        public _prepare(): void {
+        }
+
+        /**
+         * Execute the action and stop the sound.
+         */
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.stop();
+        }
+
+        /**
+         * Serializes the actions and its related information.
+         * @param parent defines the object to serialize in
+         * @returns the serialized object
+         */
+        public serialize(parent: any): any {
+            return super._serialize({
+                name: "StopSoundAction",
+                properties: [{ name: "sound", value: this._sound.name }]
+            }, parent);
+        }
+    }
+} 

+ 386 - 0
src/Audio/babylon.audioSceneComponent.ts

@@ -0,0 +1,386 @@
+module BABYLON {
+    // Adds the parser to the scene parsers.
+    AbstractScene.AddParser(SceneComponentConstants.NAME_AUDIO, (parsedData: any, scene: Scene, container: AssetContainer, rootUrl: string) => {
+        // TODO: add sound
+        var loadedSounds: Sound[] = [];
+        var loadedSound: Sound;
+        if (parsedData.sounds !== undefined && parsedData.sounds !== null) {
+            for (let index = 0, cache = parsedData.sounds.length; index < cache; index++) {
+                var 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 = [];
+    });
+
+    export interface AbstractScene {
+        /**
+         * The list of sounds used in the scene.
+         */
+        sounds: Array<Sound>;
+    }
+
+    export interface Scene {
+        /** 
+         * @hidden
+         * Backing field
+         */
+        _mainSoundTrack: SoundTrack;
+        /** 
+         * The main sound track played by the scene.
+         * It cotains your primary collection of sounds.
+         */
+        mainSoundTrack: SoundTrack;
+        /**
+         * The list of sound tracks added to the scene
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
+         */
+        soundTracks: Array<SoundTrack>;
+
+        /**
+         * Gets a sound using a given name
+         * @param name defines the name to search for
+         * @return the found sound or null if not found at all.
+         */
+        getSoundByName(name: string): Nullable<Sound>;
+
+        /**
+         * Gets or sets if audio support is enabled
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
+         */
+        audioEnabled: boolean;
+
+        /**
+         * Gets or sets if audio will be output to headphones
+         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
+         */
+        headphone: boolean;
+    }
+
+    Object.defineProperty(Scene.prototype, "mainSoundTrack", {
+        get: function (this:Scene) {
+            if (!this._mainSoundTrack) {
+                this._mainSoundTrack = new SoundTrack(this, { mainTrack: true });
+            }
+
+            return this._mainSoundTrack;
+        },
+        enumerable: true,
+        configurable: true
+    });
+
+    Scene.prototype.getSoundByName = function(name: string): Nullable<Sound> {
+        var index: number;
+        for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) {
+            if (this.mainSoundTrack.soundCollection[index].name === name) {
+                return this.mainSoundTrack.soundCollection[index];
+            }
+        }
+
+        for (var 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 (this:Scene) {
+            const compo = this._getComponent(SceneComponentConstants.NAME_AUDIO) as AudioSceneComponent;
+            if (!compo) {
+                return false;
+            }
+
+            return compo.audioEnabled;
+        },
+        set: function(this:Scene, value: boolean) {
+            const compo = this._getComponent(SceneComponentConstants.NAME_AUDIO) as AudioSceneComponent;
+            if (compo) {
+                if (value) {
+                    compo.enableAudio();
+                }
+                else {
+                    compo.disableAudio();
+                }
+            }
+        },
+        enumerable: true,
+        configurable: true
+    });
+
+    Object.defineProperty(Scene.prototype, "headphone", {
+        get: function (this:Scene) {
+            const compo = this._getComponent(SceneComponentConstants.NAME_AUDIO) as AudioSceneComponent;
+            if (!compo) {
+                return false;
+            }
+
+            return compo.headphone;
+        },
+        set: function(this:Scene, value: boolean) {
+            const compo = this._getComponent(SceneComponentConstants.NAME_AUDIO) as AudioSceneComponent;
+            if (compo) {
+                if (value) {
+                    compo.switchAudioModeForHeadphones();
+                }
+                else {
+                    compo.switchAudioModeForNormalSpeakers();
+                }
+            }
+        },
+        enumerable: true,
+        configurable: true
+    });
+
+    /**
+     * Defines the sound scene component responsible to manage any sounds
+     * in a given scene.
+     */
+    export class AudioSceneComponent implements ISceneSerializableComponent {
+        /**
+         * The component name helpfull to identify the component in the list of scene components.
+         */
+        public readonly name = SceneComponentConstants.NAME_AUDIO;
+
+        /**
+         * The scene the component belongs to.
+         */
+        public scene: Scene;
+
+        private _audioEnabled = true;
+        /**
+         * Gets whether audio is enabled or not.
+         * Please use related enable/disable method to switch state.
+         */
+        public get audioEnabled(): boolean {
+            return this._audioEnabled;
+        }
+
+        private _headphone = false;
+        /**
+         * Gets whether audio is outputing to headphone or not.
+         * Please use the according Switch methods to change output.
+         */
+        public get headphone(): boolean {
+            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: Scene) {
+            this.scene = scene;
+
+            scene.soundTracks = new Array<SoundTrack>();
+            scene.sounds = new Array<Sound>();
+        }
+
+        /**
+         * Registers the component in a given scene
+         */
+        public register(): void {
+            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.
+         */
+        public rebuild(): void {
+            // Nothing to do here. (Not rendering related)
+        }
+
+        /**
+         * Serializes the component data to the specified json object
+         * @param serializationObject The object to serialize to
+         */
+        public serialize(serializationObject: any): void {
+            serializationObject.sounds = [];
+
+            for (var index = 0; index < this.scene.soundTracks.length; index++) {
+                var soundtrack = this.scene.soundTracks[index];
+
+                for (var soundId = 0; soundId < soundtrack.soundCollection.length; soundId++) {
+                    serializationObject.sounds.push(soundtrack.soundCollection[soundId].serialize());
+                }
+            }
+        }
+
+        /**
+         * Adds all the element from the container to the scene
+         * @param container the container holding the elements
+         */
+        public addFromContainer(container: AbstractScene): void {
+            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 
+         */
+        public removeFromContainer(container: AbstractScene): void {
+            if (!container.sounds) {
+                return;
+            }
+            container.sounds.forEach((sound) => {
+                sound.stop();
+                sound.autoplay = false;
+                this.scene.mainSoundTrack.RemoveSound(sound);
+            });
+        }
+
+        /**
+         * Disposes the component and the associated ressources.
+         */
+        public dispose(): void {
+            const scene = this.scene;
+            if (scene._mainSoundTrack) {
+                scene.mainSoundTrack.dispose();
+            }
+
+            for (var scIndex = 0; scIndex < scene.soundTracks.length; scIndex++) {
+                scene.soundTracks[scIndex].dispose();
+            }
+        }
+
+        /**
+         * Disables audio in the associated scene.
+         */
+        public disableAudio() {
+            const scene = this.scene;
+            this._audioEnabled = false;
+
+            let i: number;
+            for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
+                scene.mainSoundTrack.soundCollection[i].pause();
+            }
+            for (i = 0; i < scene.soundTracks.length; i++) {
+                for (var j = 0; j < scene.soundTracks[i].soundCollection.length; j++) {
+                    scene.soundTracks[i].soundCollection[j].pause();
+                }
+            }
+        }
+
+        /**
+         * Enables audio in the associated scene.
+         */
+        public enableAudio() {
+            const scene = this.scene;
+            this._audioEnabled = true;
+
+            let i: number;
+            for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
+                if (scene.mainSoundTrack.soundCollection[i].isPaused) {
+                    scene.mainSoundTrack.soundCollection[i].play();
+                }
+            }
+            for (i = 0; i < scene.soundTracks.length; i++) {
+                for (var 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.
+         */
+        public switchAudioModeForHeadphones() {
+            const scene = this.scene;
+            this._headphone = true;
+
+            scene.mainSoundTrack.switchPanningModelToHRTF();
+
+            for (var i = 0; i < scene.soundTracks.length; i++) {
+                scene.soundTracks[i].switchPanningModelToHRTF();
+            }
+        }
+
+        /**
+         * Switch audio to normal speakers.
+         */
+        public switchAudioModeForNormalSpeakers() {
+            const scene = this.scene;
+            this._headphone = false;
+
+            scene.mainSoundTrack.switchPanningModelToEqualPower();
+
+            for (var i = 0; i < scene.soundTracks.length; i++) {
+                scene.soundTracks[i].switchPanningModelToEqualPower();
+            }
+        }
+
+        private _afterRender() {
+            const scene = this.scene;
+            if (!this._audioEnabled || !scene._mainSoundTrack || (scene._mainSoundTrack.soundCollection.length === 0 && scene.soundTracks.length === 1)) {
+                return;
+            }
+    
+            var listeningCamera: Nullable<Camera>;
+            var audioEngine = Engine.audioEngine;
+    
+            if (scene.activeCameras.length > 0) {
+                listeningCamera = scene.activeCameras[0];
+            } else {
+                listeningCamera = scene.activeCamera;
+            }
+    
+            if (listeningCamera && audioEngine.audioContext) {
+                audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
+                // for VR cameras
+                if (listeningCamera.rigCameras && listeningCamera.rigCameras.length > 0) {
+                    listeningCamera = listeningCamera.rigCameras[0];
+                }
+                var mat = Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                // To avoid some errors on GearVR
+                if (!isNaN(cameraDirection.x) && !isNaN(cameraDirection.y) && !isNaN(cameraDirection.z)) {
+                    audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+                }
+    
+                var i: number;
+                for (i = 0; i < scene.mainSoundTrack.soundCollection.length; i++) {
+                    var sound = scene.mainSoundTrack.soundCollection[i];
+                    if (sound.useCustomAttenuation) {
+                        sound.updateDistanceFromListener();
+                    }
+                }
+                for (i = 0; i < scene.soundTracks.length; i++) {
+                    for (var j = 0; j < scene.soundTracks[i].soundCollection.length; j++) {
+                        sound = scene.soundTracks[i].soundCollection[j];
+                        if (sound.useCustomAttenuation) {
+                            sound.updateDistanceFromListener();
+                        }
+                    }
+                }
+            }
+        }
+    }
+} 

+ 0 - 25
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -247,31 +247,6 @@
                     light._waitingParentId = null;
                 }
             }
-            
-            // Sounds
-            // TODO: add sound
-            var loadedSounds: Sound[] = [];
-            var loadedSound: Sound;
-            if (AudioEngine && parsedData.sounds !== undefined && parsedData.sounds !== null) {
-                for (index = 0, cache = parsedData.sounds.length; index < cache; index++) {
-                    var 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 = [];
 
             // Connect parents & children and parse actions
             for (index = 0, cache = scene.transformNodes.length; index < cache; index++) {

+ 0 - 11
src/Tools/babylon.sceneSerializer.ts

@@ -284,17 +284,6 @@
                 serializationObject.actions = scene.actionManager.serialize("scene");
             }
 
-            // Audio
-            serializationObject.sounds = [];
-
-            for (index = 0; index < scene.soundTracks.length; index++) {
-                var soundtrack = scene.soundTracks[index];
-
-                for (var soundId = 0; soundId < soundtrack.soundCollection.length; soundId++) {
-                    serializationObject.sounds.push(soundtrack.soundCollection[soundId].serialize());
-                }
-            }
-
             // Components
             for (let component of scene._serializableComponents) {
                 component.serialize(serializationObject);

+ 0 - 5
src/babylon.abstractScene.ts

@@ -165,11 +165,6 @@
         public actionManagers = new Array<ActionManager>();
 
         /**
-         * Sounds to keep.
-         */
-        public sounds = new Array<Sound>();
-
-        /**
          * Textures to keep.
          */
         public textures = new Array<BaseTexture>();

+ 0 - 10
src/babylon.assetContainer.ts

@@ -62,11 +62,6 @@ module BABYLON {
             this.actionManagers.forEach((o) => {
                 this.scene.addActionManager(o);
             });
-            this.sounds.forEach((o) => {
-                o.play();
-                o.autoplay = true;
-                this.scene.mainSoundTrack.AddSound(o);
-            });
             this.textures.forEach((o) => {
                 this.scene.addTexture(o);
             });
@@ -116,11 +111,6 @@ module BABYLON {
             this.actionManagers.forEach((o) => {
                 this.scene.removeActionManager(o);
             });
-            this.sounds.forEach((o) => {
-                o.stop();
-                o.autoplay = false;
-                this.scene.mainSoundTrack.RemoveSound(o);
-            });
             this.textures.forEach((o) => {
                 this.scene.removeTexture(o);
             });

+ 9 - 201
src/babylon.scene.ts

@@ -873,27 +873,6 @@
         */
         public proceduralTexturesEnabled = true;
 
-        // Sound Tracks
-        private _mainSoundTrack: SoundTrack;
-        /**
-         * The list of sound tracks added to the scene
-         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
-         */
-        public soundTracks = new Array<SoundTrack>();
-        private _audioEnabled = true;
-        private _headphone = false;
-
-        /**
-         * Gets the main soundtrack associated with the scene
-         */
-        public get mainSoundTrack(): SoundTrack {
-            if (!this._mainSoundTrack) {
-                this._mainSoundTrack = new SoundTrack(this, { mainTrack: true });
-            }
-
-            return this._mainSoundTrack;
-        }
-
         // Private
         private _engine: Engine;
 
@@ -1138,6 +1117,11 @@
         public _afterCameraDrawStage = Stage.Create<CameraStageAction>();
         /**
          * @hidden
+         * Defines the actions happening just after rendering all cameras and computing intersections.
+         */
+        public _afterRenderStage = Stage.Create<SimpleStageAction>();
+        /**
+         * @hidden
          * Defines the actions happening when a pointer move event happens.
          */
         public _pointerMoveStage = Stage.Create<PointerMoveStageAction>();
@@ -3783,32 +3767,6 @@
         }
 
         /**
-         * Gets a sound using a given name
-         * @param name defines the name to search for
-         * @return the found sound or null if not found at all.
-         */
-        public getSoundByName(name: string): Nullable<Sound> {
-            var index: number;
-            if (AudioEngine) {
-                for (index = 0; index < this.mainSoundTrack.soundCollection.length; index++) {
-                    if (this.mainSoundTrack.soundCollection[index].name === name) {
-                        return this.mainSoundTrack.soundCollection[index];
-                    }
-                }
-
-                for (var 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;
-        }
-
-        /**
          * Gets a skeleton using a given id (if many are found, this function will pick the last one)
          * @param id defines the id to search for
          * @return the found skeleton or null if not found at all.
@@ -4562,9 +4520,9 @@
             // Intersection checks
             this._checkIntersections();
 
-            // Update the audio listener attached to the camera
-            if (AudioEngine) {
-                this._updateAudioParameters();
+            // Executes the after render stage actions.
+            for (let step of this._afterRenderStage) {
+                step.action();
             }
 
             // After render
@@ -4593,137 +4551,6 @@
             this._activeParticles.addCount(0, true);
         }
 
-        private _updateAudioParameters() {
-            if (!this.audioEnabled || !this._mainSoundTrack || (this._mainSoundTrack.soundCollection.length === 0 && this.soundTracks.length === 1)) {
-                return;
-            }
-
-            var listeningCamera: Nullable<Camera>;
-            var audioEngine = Engine.audioEngine;
-
-            if (this.activeCameras.length > 0) {
-                listeningCamera = this.activeCameras[0];
-            } else {
-                listeningCamera = this.activeCamera;
-            }
-
-            if (listeningCamera && audioEngine.audioContext) {
-                audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
-                // for VR cameras
-                if (listeningCamera.rigCameras && listeningCamera.rigCameras.length > 0) {
-                    listeningCamera = listeningCamera.rigCameras[0];
-                }
-                var mat = Matrix.Invert(listeningCamera.getViewMatrix());
-                var cameraDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), mat);
-                cameraDirection.normalize();
-                // To avoid some errors on GearVR
-                if (!isNaN(cameraDirection.x) && !isNaN(cameraDirection.y) && !isNaN(cameraDirection.z)) {
-                    audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
-                }
-
-                var i: number;
-                for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
-                    var sound = this.mainSoundTrack.soundCollection[i];
-                    if (sound.useCustomAttenuation) {
-                        sound.updateDistanceFromListener();
-                    }
-                }
-                for (i = 0; i < this.soundTracks.length; i++) {
-                    for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
-                        sound = this.soundTracks[i].soundCollection[j];
-                        if (sound.useCustomAttenuation) {
-                            sound.updateDistanceFromListener();
-                        }
-                    }
-                }
-            }
-        }
-
-        // Audio
-        /**
-         * Gets or sets if audio support is enabled
-         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
-         */
-        public get audioEnabled(): boolean {
-            return this._audioEnabled;
-        }
-
-        public set audioEnabled(value: boolean) {
-            this._audioEnabled = value;
-            if (AudioEngine) {
-                if (this._audioEnabled) {
-                    this._enableAudio();
-                }
-                else {
-                    this._disableAudio();
-                }
-            }
-        }
-
-        private _disableAudio() {
-            var i: number;
-            for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
-                this.mainSoundTrack.soundCollection[i].pause();
-            }
-            for (i = 0; i < this.soundTracks.length; i++) {
-                for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
-                    this.soundTracks[i].soundCollection[j].pause();
-                }
-            }
-        }
-
-        private _enableAudio() {
-            var i: number;
-            for (i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
-                if (this.mainSoundTrack.soundCollection[i].isPaused) {
-                    this.mainSoundTrack.soundCollection[i].play();
-                }
-            }
-            for (i = 0; i < this.soundTracks.length; i++) {
-                for (var j = 0; j < this.soundTracks[i].soundCollection.length; j++) {
-                    if (this.soundTracks[i].soundCollection[j].isPaused) {
-                        this.soundTracks[i].soundCollection[j].play();
-                    }
-                }
-            }
-        }
-
-        /**
-         * Gets or sets if audio will be output to headphones
-         * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
-         */
-        public get headphone(): boolean {
-            return this._headphone;
-        }
-
-        public set headphone(value: boolean) {
-            this._headphone = value;
-            if (AudioEngine) {
-                if (this._headphone) {
-                    this._switchAudioModeForHeadphones();
-                }
-                else {
-                    this._switchAudioModeForNormalSpeakers();
-                }
-            }
-        }
-
-        private _switchAudioModeForHeadphones() {
-            this.mainSoundTrack.switchPanningModelToHRTF();
-
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToHRTF();
-            }
-        }
-
-        private _switchAudioModeForNormalSpeakers() {
-            this.mainSoundTrack.switchPanningModelToEqualPower();
-
-            for (var i = 0; i < this.soundTracks.length; i++) {
-                this.soundTracks[i].switchPanningModelToEqualPower();
-            }
-        }
-
         /** 
          * Freeze all materials
          * A frozen material will not be updatable but should be faster to render
@@ -4765,6 +4592,7 @@
             this._afterRenderingMeshStage.clear();
             this._afterRenderingGroupDrawStage.clear();
             this._afterCameraDrawStage.clear();
+            this._afterRenderStage.clear();
             this._beforeCameraUpdateStage.clear();
             this._beforeClearStage.clear();
             this._gatherRenderTargetsStage.clear();
@@ -4829,11 +4657,6 @@
 
             this.detachControl();
 
-            // Release sounds & sounds tracks
-            if (AudioEngine) {
-                this.disposeSounds();
-            }
-
             // Detach cameras
             var canvas = this._engine.getRenderingCanvas();
 
@@ -4922,21 +4745,6 @@
         }
 
         /**
-         *  Releases sounds & soundtracks
-         */
-        public disposeSounds() {
-            if (!this._mainSoundTrack) {
-                return;
-            }
-
-            this.mainSoundTrack.dispose();
-
-            for (var scIndex = 0; scIndex < this.soundTracks.length; scIndex++) {
-                this.soundTracks[scIndex].dispose();
-            }
-        }
-
-        /**
          * Call this function to reduce memory footprint of the scene.
          * Vertex buffers will not store CPU data anymore (this will prevent picking, collisions or physics to work correctly)
          */

+ 3 - 0
src/babylon.sceneComponent.ts

@@ -20,6 +20,7 @@
         public static readonly NAME_SHADOWGENERATOR = "ShadowGenerator";
         public static readonly NAME_OCTREE = "Octree";
         public static readonly NAME_PHYSICSENGINE = "PhysicsEngine";
+        public static readonly NAME_AUDIO = "Audio";
 
         public static readonly STEP_ISREADYFORMESH_EFFECTLAYER = 0;
 
@@ -51,6 +52,8 @@
         public static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW = 2;
         public static readonly STEP_AFTERCAMERADRAW_LAYER = 3;
 
+        public static readonly STEP_AFTERRENDER_AUDIO = 0;
+
         public static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR = 0;
         public static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER = 1;
         public static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 2;