BabylonJS - Playing Sounds and Music



Without sound and music, a game is incomplete. BabylonJS sound engine comes with an API that helps to add sound effects to the game. When there is a fight seen in the game, you need to get the gunshot firing, the same can be achieved over here with babylonjs sound engine. You can get the sound effect based on the keyboard/mouse controls effect to the games. The sound engine offers ambient sound, specialized sound and directional sound. The engine supports .mp3 and .wav sound formats.

Syntax

var music = new BABYLON.Sound(
   "Music", "sound.wav", scene, null, { 
      loop: true, 
      autoplay: true 
   }
);

Parameters

Consider the following parameters related to the sound engine −

  • Name − Name of the sound.

  • URL − url of the sound to be played.

  • Scene − Scene to which the sound has to be played.

  • Callbackfunction − The callbackfunction which is called when the sound is ready to be played.At present, it is null. We will go through a few examples and learn how to use it.

  • Json object − This object has basic details of what needs to be done.

  • sound.autoplay − With this, the sound plays automatically once the file is downloaded.

  • loop:true − This means the sound will continuously play in a loop.

Create sound folder in your project directory and download any sample audio file to test the output.

Let us now add sound to the scene that we have already created.

Demo

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Scene- Playing sounds and music</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>
   
   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 1, 0);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);
            
            var music = new BABYLON.Sound("sound", "sounds/scooby.wav", scene, null, { 
               loop: true, 
               autoplay: true 
            });	
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

Output

The above line of code generates the following output −

Basic Scene Without Sound

Let us now check how the callback function works. If you do not want the sound to autoplay or you want to play the sound only when you want, you can do so with the callback function.

For example,

Var music = new BABYLON.Sound ("Music", "music.wav", scene, function callback() {music.play();});

Demo

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Scene- Playing sounds and music</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 1, 0);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true)
            
            var music = new BABYLON.Sound(
               "sound", "sounds/scooby.wav", scene, function callback() { setTimeout(function() {music.play();}, 5000)});	
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

In the callback,we will use setTimeout. This means, we want the sound to be played only after a specific time. We have added 5s as a timer to it, so the sound will play when the files Scooby.wav is downloaded and 5s complete.

Play sounds with clicks and keys on the keyboard

Upon clicking anywhere on the scene, you will hear explosive sound effect and if you press any of the arrow keys -left, right, up or down, it will play the explosive sound effect.

For click, we are attaching the event onmousedown to the window and for keys, we will use the keydown event. Based on keycode, the sound is played.

Demo

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Scene- Playing sounds and music</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 1, 0);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true)
            
            var sound = new BABYLON.Sound("gunshot", "sounds/explosion.wav", scene);

            window.addEventListener("mousedown", function (evt) {	
               if (evt.button === 0) { // onclick
                  sound.play();
               }
            });

            window.addEventListener("keydown", function (evt) { // arrow key left right up down
               if (evt.keyCode === 37 || evt.keyCode === 38 || evt.keyCode === 39 || evt.keyCode === 40) {
                  sound.play();
               }
            });		
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

Output

The above line of code will generate the following output −

Basic Scene Without Sound

You can control the volume of the sound in the json object, which we encountered in the beginning.

For example,

Var music = new BABYLON.Sound("sound", "sounds/scooby.wav", scene, null, { 
   loop: true, 
   autoplay: true, 
   volume:0.5 
});

To know when a sound file has finished, there is an event which can be used as follows −

music.onended = function () {	
   console.log("sound ended");
   
   //you can do the required stuff here like play it again or play some other sound etc.
};

The SetVolume property is also available in case you want to control the sound besides the constructor.

For example,

music.setVolume(volume);

If you are playing more than one sound in your scene, you can set a global sound for all the sounds created.

For example,

BABYLON.Engine.audioEngine.setGlobalVolume(0.5);

Creating a Spatial 3D Sound

If you want to convert the sound to spatial sound (sound similar to space sound), you need to add options to your sound constructor.

For example,

var music = new BABYLON.Sound("music", "sounds/explosion.wav", scene, null, { 
   loop: false, 
   autoplay: true, 
   spatialSound: true 
});

Following are the different options for spatial sound −

  • DistanceModel − It is using a “linear” equation by default. Other options are “inverse” or “exponential”.

  • MaxDistance − It is set to 100. This means that once the listener is farther than 100 units from the sound, the volume will be 0. You can’t hear the sound anymore

  • PanningModel − It is set to “HRTF”. The specification says it isa higher quality spatialization algorithm using a convolution with measured impulse responses from human subjects. It refers to the stereo output.

  • MaxDistance − It is used only when distanceModel is linear.It is not used with inverse or exponential.

Demo with spatial sound

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Scene- Playing sounds and music</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 1, 0);
            
            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);	
            
            var music = new BABYLON.Sound(
               "music", "sounds/explosion.wav", scene, null, {
                  loop: false, autoplay: true, spatialSound: true, distanceModel: "exponential"
               }
            );
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

Attaching sound to a mesh

Using BABYLON.Sound, you can attach sound to your mesh. If the mesh is moving, the sound will move along with it. AttachtoMesh (mesh) is the method to be used.

Demo

<!doctype html>
<html>
   <head>
      <meta charset = "utf-8">
      <title>BabylonJs - Basic Scene- Playing sounds and music</title>
      <script src = "babylon.js"></script>
      <style>
         canvas {width: 100%; height: 100%;}
      </style>
   </head>

   <body>
      <canvas id = "renderCanvas"></canvas>
      <script type = "text/javascript">
         var canvas = document.getElementById("renderCanvas");
         var engine = new BABYLON.Engine(canvas, true);
         var createScene  = function() {
            var scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3(0, 1, 0);

            var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
            camera.attachControl(canvas, true);

            var materialforbox = new BABYLON.StandardMaterial("texture1", scene);
            var box = BABYLON.Mesh.CreateBox("box", '2', scene);	
            box.material  = materialforbox;
            materialforbox.ambientColor = new BABYLON.Color3(1, 0, 0.2);

            var music = new BABYLON.Sound("music", "sounds/explosion.wav", scene, null, { 
               loop: false, 
               autoplay: true, 
               spatialSound: true, 
               distanceModel: "exponential"
            });	
            music.attachToMesh(box);
            return scene;
         };
         var scene = createScene();
         engine.runRenderLoop(function() {
            scene.render();
         });
      </script>
   </body>
</html>

Output

The above line of code generates the following output −

Spatial 3D Sound
Advertisements