babylon.sound.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. var BABYLON;
  2. (function (BABYLON) {
  3. var Sound = (function () {
  4. /**
  5. * Create a sound and attach it to a scene
  6. * @param name Name of your sound
  7. * @param url Url to the sound to load async
  8. * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
  9. * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
  10. */
  11. function Sound(name, url, scene, readyToPlayCallback, options) {
  12. var _this = this;
  13. this.maxDistance = 20;
  14. this.autoplay = false;
  15. this.loop = false;
  16. this.useBabylonJSAttenuation = true;
  17. this._position = BABYLON.Vector3.Zero();
  18. this._localDirection = new BABYLON.Vector3(1, 0, 0);
  19. this._volume = 1;
  20. this._isLoaded = false;
  21. this._isReadyToPlay = false;
  22. this._isPlaying = false;
  23. this._isDirectional = false;
  24. // Used if you'd like to create a directional sound.
  25. // If not set, the sound will be omnidirectional
  26. this._coneInnerAngle = null;
  27. this._coneOuterAngle = null;
  28. this._coneOuterGain = null;
  29. this._name = name;
  30. this._scene = scene;
  31. this._audioEngine = this._scene.getEngine().getAudioEngine();
  32. this._readyToPlayCallback = readyToPlayCallback;
  33. if (options) {
  34. if (options.maxDistance) {
  35. this.maxDistance = options.maxDistance;
  36. }
  37. if (options.autoplay) {
  38. this.autoplay = options.autoplay;
  39. }
  40. if (options.loop) {
  41. this.loop = options.loop;
  42. }
  43. if (options.volume) {
  44. this._volume = options.volume;
  45. }
  46. if (options.useBabylonJSAttenuation) {
  47. this.useBabylonJSAttenuation = options.useBabylonJSAttenuation;
  48. }
  49. }
  50. if (this._audioEngine.canUseWebAudio) {
  51. this._soundGain = this._audioEngine.audioContext.createGain();
  52. this._soundGain.gain.value = this._volume;
  53. //this._soundGain.connect(this._audioEngine.masterGain);
  54. this._soundPanner = this._audioEngine.audioContext.createPanner();
  55. this._soundPanner.connect(this._soundGain);
  56. this._scene.mainSoundTrack.AddSound(this);
  57. BABYLON.Tools.LoadFile(url, function (data) {
  58. _this._soundLoaded(data);
  59. }, null, null, true);
  60. }
  61. }
  62. Sound.prototype.connectToSoundTrackAudioNode = function (soundTrackAudioNode) {
  63. if (this._audioEngine.canUseWebAudio) {
  64. this._soundGain.disconnect();
  65. this._soundGain.connect(soundTrackAudioNode);
  66. }
  67. };
  68. /**
  69. * Transform this sound into a directional source
  70. * @param coneInnerAngle Size of the inner cone in degree
  71. * @param coneOuterAngle Size of the outer cone in degree
  72. * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
  73. */
  74. Sound.prototype.setDirectionalCone = function (coneInnerAngle, coneOuterAngle, coneOuterGain) {
  75. if (coneOuterAngle < coneInnerAngle) {
  76. BABYLON.Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
  77. return;
  78. }
  79. this._coneInnerAngle = coneInnerAngle;
  80. this._coneOuterAngle = coneOuterAngle;
  81. this._coneOuterGain = coneOuterGain;
  82. this._isDirectional = true;
  83. if (this._isPlaying && this.loop) {
  84. this.stop();
  85. this.play();
  86. }
  87. };
  88. Sound.prototype.setPosition = function (newPosition) {
  89. this._position = newPosition;
  90. if (this._isPlaying) {
  91. this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
  92. }
  93. };
  94. Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
  95. this._localDirection = newLocalDirection;
  96. if (this._connectedMesh && this._isPlaying) {
  97. this._updateDirection();
  98. }
  99. };
  100. Sound.prototype._updateDirection = function () {
  101. var mat = this._connectedMesh.getWorldMatrix();
  102. var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
  103. direction.normalize();
  104. this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
  105. };
  106. Sound.prototype.updateDistanceFromListener = function () {
  107. if (this._connectedMesh) {
  108. var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
  109. if (distance < 1)
  110. distance = 1;
  111. if (this.useBabylonJSAttenuation) {
  112. if (distance < this.maxDistance) {
  113. this._soundGain.gain.value = this._volume / distance;
  114. } else {
  115. this._soundGain.gain.value = 0;
  116. }
  117. }
  118. }
  119. };
  120. /**
  121. * Play the sound
  122. * @param time (optional) Start the sound after X seconds. Start immediately (0) by default.
  123. */
  124. Sound.prototype.play = function (time) {
  125. if (this._isReadyToPlay) {
  126. try {
  127. var startTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
  128. this._soundSource = this._audioEngine.audioContext.createBufferSource();
  129. this._soundSource.buffer = this._audioBuffer;
  130. this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
  131. if (this._isDirectional) {
  132. this._soundPanner.coneInnerAngle = this._coneInnerAngle;
  133. this._soundPanner.coneOuterAngle = this._coneOuterAngle;
  134. this._soundPanner.coneOuterGain = this._coneOuterGain;
  135. this._soundPanner.setOrientation(this._localDirection.x, this._localDirection.y, this._localDirection.z);
  136. }
  137. this._soundSource.connect(this._soundPanner);
  138. this._soundSource.loop = this.loop;
  139. this._soundSource.start(startTime);
  140. this._isPlaying = true;
  141. } catch (ex) {
  142. BABYLON.Tools.Error("Error while trying to play audio: " + this._name + ", " + ex.message);
  143. }
  144. }
  145. };
  146. /**
  147. * Stop the sound
  148. * @param time (optional) Stop the sound after X seconds. Stop immediately (0) by default.
  149. */
  150. Sound.prototype.stop = function (time) {
  151. var stopTime = time ? this._audioEngine.audioContext.currentTime + time : 0;
  152. this._soundSource.stop(stopTime);
  153. this._isPlaying = false;
  154. };
  155. Sound.prototype.pause = function () {
  156. //this._soundSource.p
  157. };
  158. Sound.prototype.setVolume = function (newVolume) {
  159. this._volume = newVolume;
  160. };
  161. Sound.prototype.getVolume = function () {
  162. return this._volume;
  163. };
  164. Sound.prototype.attachToMesh = function (meshToConnectTo) {
  165. var _this = this;
  166. this._connectedMesh = meshToConnectTo;
  167. meshToConnectTo.registerAfterWorldMatrixUpdate(function (connectedMesh) {
  168. return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh);
  169. });
  170. };
  171. Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
  172. this.setPosition(connectedMesh.position);
  173. if (this._isDirectional && this._isPlaying) {
  174. this._updateDirection();
  175. }
  176. };
  177. Sound.prototype._soundLoaded = function (audioData) {
  178. var _this = this;
  179. this._isLoaded = true;
  180. this._audioEngine.audioContext.decodeAudioData(audioData, function (buffer) {
  181. _this._audioBuffer = buffer;
  182. _this._isReadyToPlay = true;
  183. if (_this.autoplay) {
  184. _this.play();
  185. }
  186. if (_this._readyToPlayCallback) {
  187. _this._readyToPlayCallback();
  188. }
  189. }, function (error) {
  190. BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
  191. });
  192. };
  193. return Sound;
  194. })();
  195. BABYLON.Sound = Sound;
  196. })(BABYLON || (BABYLON = {}));
  197. //# sourceMappingURL=babylon.sound.js.map