UNPKG

11.1 kBJavaScriptView Raw
1import { Vector3 } from "@babylonjs/core/Maths/math";
2import { Tools } from "@babylonjs/core/Misc/tools";
3import { AnimationEvent } from "@babylonjs/core/Animations/animationEvent";
4import { Sound } from "@babylonjs/core/Audio/sound";
5import { WeightedSound } from "@babylonjs/core/Audio/weightedsound";
6import { GLTFLoader, ArrayItem } from "../glTFLoader";
7var NAME = "MSFT_audio_emitter";
8/**
9 * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
10 */
11var MSFT_audio_emitter = /** @class */ (function () {
12 /** @hidden */
13 function MSFT_audio_emitter(loader) {
14 /** The name of this extension. */
15 this.name = NAME;
16 /** Defines whether this extension is enabled. */
17 this.enabled = true;
18 this._loader = loader;
19 }
20 /** @hidden */
21 MSFT_audio_emitter.prototype.dispose = function () {
22 delete this._loader;
23 delete this._clips;
24 delete this._emitters;
25 };
26 /** @hidden */
27 MSFT_audio_emitter.prototype.onLoading = function () {
28 var extensions = this._loader.gltf.extensions;
29 if (extensions && extensions[this.name]) {
30 var extension = extensions[this.name];
31 this._clips = extension.clips;
32 this._emitters = extension.emitters;
33 ArrayItem.Assign(this._clips);
34 ArrayItem.Assign(this._emitters);
35 }
36 };
37 /** @hidden */
38 MSFT_audio_emitter.prototype.loadSceneAsync = function (context, scene) {
39 var _this = this;
40 return GLTFLoader.LoadExtensionAsync(context, scene, this.name, function (extensionContext, extension) {
41 var promises = new Array();
42 promises.push(_this._loader.loadSceneAsync(context, scene));
43 for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
44 var emitterIndex = _a[_i];
45 var emitter = ArrayItem.Get(extensionContext + "/emitters", _this._emitters, emitterIndex);
46 if (emitter.refDistance != undefined || emitter.maxDistance != undefined || emitter.rolloffFactor != undefined ||
47 emitter.distanceModel != undefined || emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
48 throw new Error(extensionContext + ": Direction or Distance properties are not allowed on emitters attached to a scene");
49 }
50 promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter.index, emitter));
51 }
52 return Promise.all(promises).then(function () { });
53 });
54 };
55 /** @hidden */
56 MSFT_audio_emitter.prototype.loadNodeAsync = function (context, node, assign) {
57 var _this = this;
58 return GLTFLoader.LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
59 var promises = new Array();
60 return _this._loader.loadNodeAsync(extensionContext, node, function (babylonMesh) {
61 var _loop_1 = function (emitterIndex) {
62 var emitter = ArrayItem.Get(extensionContext + "/emitters", _this._emitters, emitterIndex);
63 promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter.index, emitter).then(function () {
64 for (var _i = 0, _a = emitter._babylonSounds; _i < _a.length; _i++) {
65 var sound = _a[_i];
66 sound.attachToMesh(babylonMesh);
67 if (emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
68 sound.setLocalDirectionToMesh(Vector3.Forward());
69 sound.setDirectionalCone(2 * Tools.ToDegrees(emitter.innerAngle == undefined ? Math.PI : emitter.innerAngle), 2 * Tools.ToDegrees(emitter.outerAngle == undefined ? Math.PI : emitter.outerAngle), 0);
70 }
71 }
72 }));
73 };
74 for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
75 var emitterIndex = _a[_i];
76 _loop_1(emitterIndex);
77 }
78 assign(babylonMesh);
79 }).then(function (babylonMesh) {
80 return Promise.all(promises).then(function () {
81 return babylonMesh;
82 });
83 });
84 });
85 };
86 /** @hidden */
87 MSFT_audio_emitter.prototype.loadAnimationAsync = function (context, animation) {
88 var _this = this;
89 return GLTFLoader.LoadExtensionAsync(context, animation, this.name, function (extensionContext, extension) {
90 return _this._loader.loadAnimationAsync(context, animation).then(function (babylonAnimationGroup) {
91 var promises = new Array();
92 ArrayItem.Assign(extension.events);
93 for (var _i = 0, _a = extension.events; _i < _a.length; _i++) {
94 var event_1 = _a[_i];
95 promises.push(_this._loadAnimationEventAsync(extensionContext + "/events/" + event_1.index, context, animation, event_1, babylonAnimationGroup));
96 }
97 return Promise.all(promises).then(function () {
98 return babylonAnimationGroup;
99 });
100 });
101 });
102 };
103 MSFT_audio_emitter.prototype._loadClipAsync = function (context, clip) {
104 if (clip._objectURL) {
105 return clip._objectURL;
106 }
107 var promise;
108 if (clip.uri) {
109 promise = this._loader.loadUriAsync(context, clip, clip.uri);
110 }
111 else {
112 var bufferView = ArrayItem.Get(context + "/bufferView", this._loader.gltf.bufferViews, clip.bufferView);
113 promise = this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView);
114 }
115 clip._objectURL = promise.then(function (data) {
116 return URL.createObjectURL(new Blob([data], { type: clip.mimeType }));
117 });
118 return clip._objectURL;
119 };
120 MSFT_audio_emitter.prototype._loadEmitterAsync = function (context, emitter) {
121 var _this = this;
122 emitter._babylonSounds = emitter._babylonSounds || [];
123 if (!emitter._babylonData) {
124 var clipPromises = new Array();
125 var name_1 = emitter.name || "emitter" + emitter.index;
126 var options_1 = {
127 loop: false,
128 autoplay: false,
129 volume: emitter.volume == undefined ? 1 : emitter.volume,
130 };
131 var _loop_2 = function (i) {
132 var clipContext = "#/extensions/" + this_1.name + "/clips";
133 var clip = ArrayItem.Get(clipContext, this_1._clips, emitter.clips[i].clip);
134 clipPromises.push(this_1._loadClipAsync(clipContext + "/" + emitter.clips[i].clip, clip).then(function (objectURL) {
135 var sound = emitter._babylonSounds[i] = new Sound(name_1, objectURL, _this._loader.babylonScene, null, options_1);
136 sound.refDistance = emitter.refDistance || 1;
137 sound.maxDistance = emitter.maxDistance || 256;
138 sound.rolloffFactor = emitter.rolloffFactor || 1;
139 sound.distanceModel = emitter.distanceModel || 'exponential';
140 sound._positionInEmitterSpace = true;
141 }));
142 };
143 var this_1 = this;
144 for (var i = 0; i < emitter.clips.length; i++) {
145 _loop_2(i);
146 }
147 var promise = Promise.all(clipPromises).then(function () {
148 var weights = emitter.clips.map(function (clip) { return clip.weight || 1; });
149 var weightedSound = new WeightedSound(emitter.loop || false, emitter._babylonSounds, weights);
150 if (emitter.innerAngle) {
151 weightedSound.directionalConeInnerAngle = 2 * Tools.ToDegrees(emitter.innerAngle);
152 }
153 if (emitter.outerAngle) {
154 weightedSound.directionalConeOuterAngle = 2 * Tools.ToDegrees(emitter.outerAngle);
155 }
156 if (emitter.volume) {
157 weightedSound.volume = emitter.volume;
158 }
159 emitter._babylonData.sound = weightedSound;
160 });
161 emitter._babylonData = {
162 loaded: promise
163 };
164 }
165 return emitter._babylonData.loaded;
166 };
167 MSFT_audio_emitter.prototype._getEventAction = function (context, sound, action, time, startOffset) {
168 switch (action) {
169 case "play" /* play */: {
170 return function (currentFrame) {
171 var frameOffset = (startOffset || 0) + (currentFrame - time);
172 sound.play(frameOffset);
173 };
174 }
175 case "stop" /* stop */: {
176 return function (currentFrame) {
177 sound.stop();
178 };
179 }
180 case "pause" /* pause */: {
181 return function (currentFrame) {
182 sound.pause();
183 };
184 }
185 default: {
186 throw new Error(context + ": Unsupported action " + action);
187 }
188 }
189 };
190 MSFT_audio_emitter.prototype._loadAnimationEventAsync = function (context, animationContext, animation, event, babylonAnimationGroup) {
191 var _this = this;
192 if (babylonAnimationGroup.targetedAnimations.length == 0) {
193 return Promise.resolve();
194 }
195 var babylonAnimation = babylonAnimationGroup.targetedAnimations[0];
196 var emitterIndex = event.emitter;
197 var emitter = ArrayItem.Get("#/extensions/" + this.name + "/emitters", this._emitters, emitterIndex);
198 return this._loadEmitterAsync(context, emitter).then(function () {
199 var sound = emitter._babylonData.sound;
200 if (sound) {
201 var babylonAnimationEvent = new AnimationEvent(event.time, _this._getEventAction(context, sound, event.action, event.time, event.startOffset));
202 babylonAnimation.animation.addEvent(babylonAnimationEvent);
203 // Make sure all started audio stops when this animation is terminated.
204 babylonAnimationGroup.onAnimationGroupEndObservable.add(function () {
205 sound.stop();
206 });
207 babylonAnimationGroup.onAnimationGroupPauseObservable.add(function () {
208 sound.pause();
209 });
210 }
211 });
212 };
213 return MSFT_audio_emitter;
214}());
215export { MSFT_audio_emitter };
216GLTFLoader.RegisterExtension(NAME, function (loader) { return new MSFT_audio_emitter(loader); });
217//# sourceMappingURL=MSFT_audio_emitter.js.map
\No newline at end of file