@needle-tools/engine 2.63.3-pre → 2.64.0-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/needle-engine.js +9760 -9635
- package/dist/needle-engine.umd.cjs +237 -236
- package/lib/engine/engine_application.d.ts +7 -1
- package/lib/engine/engine_application.js +11 -0
- package/lib/engine/engine_application.js.map +1 -1
- package/lib/engine/engine_constants.d.ts +1 -1
- package/lib/engine/engine_constants.js +1 -1
- package/lib/engine/engine_constants.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_instancing.d.ts +1 -0
- package/lib/engine/engine_instancing.js +3 -2
- package/lib/engine/engine_instancing.js.map +1 -1
- package/lib/engine/engine_license.js +14 -13
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +27 -52
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -0
- package/lib/engine/engine_physics.js +30 -0
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +1 -0
- package/lib/engine/engine_serialization_builtin_serializer.js +30 -25
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +8 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +1 -1
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.d.ts +1 -0
- package/lib/engine/engine_time.js +5 -1
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +12 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine-components/Animation.js +6 -6
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +2 -0
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioListener.js +2 -0
- package/lib/engine-components/AudioListener.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +2 -1
- package/lib/engine-components/AudioSource.js +19 -4
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/Component.d.ts +1 -0
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/GridHelper.d.ts +1 -0
- package/lib/engine-components/GridHelper.js +7 -0
- package/lib/engine-components/GridHelper.js.map +1 -1
- package/lib/engine-components/ParticleSystem.js +13 -1
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +5 -1
- package/lib/engine-components/Renderer.js +78 -29
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +1 -0
- package/lib/engine-components/WebARSessionRoot.js +10 -0
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/js-extensions/Object3D.js +11 -1
- package/lib/engine-components/js-extensions/Object3D.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +5 -0
- package/lib/engine-components/timeline/PlayableDirector.js +36 -23
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +9 -0
- package/lib/engine-components/timeline/TimelineTracks.js +121 -21
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/engine/engine_application.ts +14 -3
- package/src/engine/engine_constants.ts +1 -1
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_instancing.ts +3 -3
- package/src/engine/engine_license.ts +14 -13
- package/src/engine/engine_mainloop_utils.ts +32 -58
- package/src/engine/engine_physics.ts +23 -0
- package/src/engine/engine_serialization_builtin_serializer.ts +36 -27
- package/src/engine/engine_serialization_core.ts +8 -1
- package/src/engine/engine_setup.ts +1 -1
- package/src/engine/engine_time.ts +9 -4
- package/src/engine/engine_types.ts +36 -22
- package/src/engine-components/Animation.ts +6 -5
- package/src/engine-components/AnimatorController.ts +1 -0
- package/src/engine-components/AudioListener.ts +1 -0
- package/src/engine-components/AudioSource.ts +20 -6
- package/src/engine-components/Component.ts +3 -0
- package/src/engine-components/GridHelper.ts +10 -2
- package/src/engine-components/ParticleSystem.ts +15 -2
- package/src/engine-components/Renderer.ts +92 -33
- package/src/engine-components/WebARSessionRoot.ts +14 -0
- package/src/engine-components/js-extensions/Object3D.ts +11 -3
- package/src/engine-components/timeline/PlayableDirector.ts +35 -24
- package/src/engine-components/timeline/TimelineTracks.ts +132 -22
- package/src/tsconfig.json +33 -0
- package/src/engine/codegen/license.js +0 -1
- /package/{src/plugins → plugins}/vite/build.js +0 -0
- /package/{src/plugins → plugins}/vite/config.js +0 -0
- /package/{src/plugins → plugins}/vite/gzip.js +0 -0
- /package/{src/plugins → plugins}/vite/index.js +0 -0
- /package/{src/plugins → plugins}/vite/meta.js +0 -0
- /package/{src/plugins → plugins}/vite/poster-client.js +0 -0
- /package/{src/plugins → plugins}/vite/poster.js +0 -0
- /package/{src/plugins → plugins}/vite/reload-client.js +0 -0
- /package/{src/plugins → plugins}/vite/reload.js +0 -0
|
@@ -84,9 +84,13 @@ export class PlayableDirector extends Behaviour {
|
|
|
84
84
|
set duration(value: number) { this._duration = value; }
|
|
85
85
|
get weight(): number { return this._weight; };
|
|
86
86
|
set weight(value: number) { this._weight = value; }
|
|
87
|
+
get speed(): number { return this._speed; }
|
|
88
|
+
set speed(value: number) { this._speed = value; }
|
|
89
|
+
|
|
87
90
|
|
|
88
91
|
private _visibilityChangeEvt?: any;
|
|
89
92
|
private _clonedPlayableAsset: boolean = false;
|
|
93
|
+
private _speed: number = 1;
|
|
90
94
|
|
|
91
95
|
awake(): void {
|
|
92
96
|
if (debug)
|
|
@@ -149,7 +153,9 @@ export class PlayableDirector extends Behaviour {
|
|
|
149
153
|
|
|
150
154
|
play() {
|
|
151
155
|
if (!this.isValid()) return;
|
|
156
|
+
const pauseChanged = this._isPaused == true;
|
|
152
157
|
this._isPaused = false;
|
|
158
|
+
if (pauseChanged) this.invokePauseChangedMethodsOnTracks();
|
|
153
159
|
if (this._isPlaying) return;
|
|
154
160
|
this._isPlaying = true;
|
|
155
161
|
this._internalUpdateRoutine = this.startCoroutine(this.internalUpdate());
|
|
@@ -161,18 +167,23 @@ export class PlayableDirector extends Behaviour {
|
|
|
161
167
|
if (this._isPaused) return;
|
|
162
168
|
this._isPaused = true;
|
|
163
169
|
this.evaluate();
|
|
170
|
+
this.invokePauseChangedMethodsOnTracks();
|
|
164
171
|
}
|
|
165
172
|
|
|
166
173
|
stop() {
|
|
167
|
-
for(const track of this._audioTracks) track.stop();
|
|
174
|
+
for (const track of this._audioTracks) track.stop();
|
|
175
|
+
const pauseChanged = this._isPaused == true;
|
|
176
|
+
const wasPlaying = this._isPlaying;
|
|
168
177
|
if (this._isPlaying) {
|
|
169
178
|
this._time = 0;
|
|
170
179
|
this._isPlaying = false;
|
|
171
180
|
this._isPaused = false;
|
|
172
181
|
this.evaluate();
|
|
182
|
+
if (pauseChanged) this.invokePauseChangedMethodsOnTracks();
|
|
173
183
|
}
|
|
174
184
|
this._isPlaying = false;
|
|
175
185
|
this._isPaused = false;
|
|
186
|
+
if (pauseChanged && !wasPlaying) this.invokePauseChangedMethodsOnTracks();
|
|
176
187
|
if (this._internalUpdateRoutine)
|
|
177
188
|
this.stopCoroutine(this._internalUpdateRoutine);
|
|
178
189
|
this._internalUpdateRoutine = null;
|
|
@@ -183,10 +194,15 @@ export class PlayableDirector extends Behaviour {
|
|
|
183
194
|
let t = this._time;
|
|
184
195
|
switch (this.extrapolationMode) {
|
|
185
196
|
case DirectorWrapMode.Hold:
|
|
186
|
-
|
|
197
|
+
if(this._speed > 0)
|
|
198
|
+
t = Math.min(t, this._duration);
|
|
199
|
+
else if(this._speed < 0)
|
|
200
|
+
t = Math.max(t, 0);
|
|
201
|
+
this._time = t;
|
|
187
202
|
break;
|
|
188
203
|
case DirectorWrapMode.Loop:
|
|
189
204
|
t %= this._duration;
|
|
205
|
+
this._time = t;
|
|
190
206
|
break;
|
|
191
207
|
case DirectorWrapMode.None:
|
|
192
208
|
if (t > this._duration) {
|
|
@@ -240,10 +256,17 @@ export class PlayableDirector extends Behaviour {
|
|
|
240
256
|
this._customTracks
|
|
241
257
|
];
|
|
242
258
|
|
|
259
|
+
/** should be called after evaluate if the director was playing */
|
|
260
|
+
private invokePauseChangedMethodsOnTracks() {
|
|
261
|
+
for (const track of this.forEachTrack()) {
|
|
262
|
+
track.onPauseChanged?.call(track);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
243
266
|
private *internalUpdate() {
|
|
244
267
|
while (this._isPlaying && this.activeAndEnabled) {
|
|
245
268
|
if (!this._isPaused && this._isPlaying) {
|
|
246
|
-
this._time += this.context.time.deltaTime;
|
|
269
|
+
this._time += this.context.time.deltaTime * this.speed;
|
|
247
270
|
this.evaluate();
|
|
248
271
|
}
|
|
249
272
|
// for (let i = 0; i < 5; i++)
|
|
@@ -278,10 +301,8 @@ export class PlayableDirector extends Behaviour {
|
|
|
278
301
|
for (const handler of this._animationTracks) {
|
|
279
302
|
handler.evaluate(time);
|
|
280
303
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
handler.evaluate(time);
|
|
284
|
-
}
|
|
304
|
+
for (const handler of this._audioTracks) {
|
|
305
|
+
handler.evaluate(time);
|
|
285
306
|
}
|
|
286
307
|
for (const sig of this._signalTracks) {
|
|
287
308
|
sig.evaluate(time);
|
|
@@ -369,8 +390,7 @@ export class PlayableDirector extends Behaviour {
|
|
|
369
390
|
this._signalTracks.length = 0;
|
|
370
391
|
|
|
371
392
|
if (!this.playableAsset) return;
|
|
372
|
-
const
|
|
373
|
-
const audioAllowedCallbacks : any = [];
|
|
393
|
+
const audioListener: AudioListener | null = GameObject.findObjectOfType(AudioListener, this.context);
|
|
374
394
|
for (const track of this.playableAsset!.tracks) {
|
|
375
395
|
const type = track.type;
|
|
376
396
|
const registered = PlayableDirector.createTrackFunctions[type];
|
|
@@ -442,16 +462,12 @@ export class PlayableDirector extends Behaviour {
|
|
|
442
462
|
audio.director = this;
|
|
443
463
|
audio.track = track;
|
|
444
464
|
this._audioTracks.push(audio);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
audio.
|
|
450
|
-
|
|
451
|
-
const clipModel = track.clips[i];
|
|
452
|
-
audio.addModel(clipModel);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
465
|
+
if (!audioListener) continue;
|
|
466
|
+
audio.listener = audioListener.listener;
|
|
467
|
+
for (let i = 0; i < track.clips.length; i++) {
|
|
468
|
+
const clipModel = track.clips[i];
|
|
469
|
+
audio.addModel(clipModel);
|
|
470
|
+
}
|
|
455
471
|
}
|
|
456
472
|
else if (track.type === Models.TrackType.Marker) {
|
|
457
473
|
const signalHandler: Tracks.SignalTrackHandler = new Tracks.SignalTrackHandler();
|
|
@@ -497,11 +513,6 @@ export class PlayableDirector extends Behaviour {
|
|
|
497
513
|
this._controlTracks.push(handler);
|
|
498
514
|
}
|
|
499
515
|
}
|
|
500
|
-
|
|
501
|
-
AudioSource.registerWaitForAllowAudio(() => {
|
|
502
|
-
audioAllowedCallbacks.forEach((cb: any) => cb());
|
|
503
|
-
audioAllowedCallbacks.length = 0;
|
|
504
|
-
});
|
|
505
516
|
}
|
|
506
517
|
|
|
507
518
|
private setAudioTracksAllowPlaying(allow: boolean) {
|
|
@@ -6,6 +6,8 @@ import { Context } from "../../engine/engine_setup";
|
|
|
6
6
|
import { SignalReceiver } from "./SignalAsset";
|
|
7
7
|
import { AnimationClip, Quaternion, Vector3 } from "three";
|
|
8
8
|
import { getParam, getPath } from "../../engine/engine_utils";
|
|
9
|
+
import { AudioSource } from "../AudioSource";
|
|
10
|
+
import { Animator } from "../Animator"
|
|
9
11
|
|
|
10
12
|
const debug = getParam("debugtimeline");
|
|
11
13
|
|
|
@@ -40,6 +42,7 @@ export abstract class TrackHandler {
|
|
|
40
42
|
onDestroy?();
|
|
41
43
|
abstract evaluate(time: number);
|
|
42
44
|
onMuteChanged?();
|
|
45
|
+
onPauseChanged?();
|
|
43
46
|
|
|
44
47
|
getClipTime(time: number, model: Models.ClipModel) {
|
|
45
48
|
return model.clipIn + (time - model.start) * model.timeScale;
|
|
@@ -136,6 +139,16 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
136
139
|
/** holds data/info about clips differences */
|
|
137
140
|
private _actionOffsets: Array<AnimationClipOffsetData> = [];
|
|
138
141
|
private _didBind: boolean = false;
|
|
142
|
+
private _animator: Animator | null = null;
|
|
143
|
+
private _animatorWasEnabled?: boolean = false;
|
|
144
|
+
|
|
145
|
+
onPauseChanged() {
|
|
146
|
+
// When the timeline is paused the original animator will be enabled again if it was before
|
|
147
|
+
if (this._animator && this._animatorWasEnabled !== undefined) {
|
|
148
|
+
this._animator.enabled = this.director.isPaused ? this._animatorWasEnabled : false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
139
152
|
|
|
140
153
|
createHooks(clipModel: Models.AnimationClipModel, clip) {
|
|
141
154
|
if (clip.tracks?.length <= 0) {
|
|
@@ -208,6 +221,13 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
208
221
|
this._actionOffsets.push(off);
|
|
209
222
|
}
|
|
210
223
|
|
|
224
|
+
if (this.target) {
|
|
225
|
+
// We need to disable the animator component in case it also animates
|
|
226
|
+
// which overrides the timeline
|
|
227
|
+
this._animator = GameObject.getComponent(this.target, Animator) ?? null;
|
|
228
|
+
this._animatorWasEnabled = this._animator?.enabled;
|
|
229
|
+
}
|
|
230
|
+
|
|
211
231
|
// Clip Offsets
|
|
212
232
|
for (const model of this.models) {
|
|
213
233
|
const clipData = model.asset as Models.AnimationClipModel;
|
|
@@ -261,6 +281,8 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
261
281
|
if (!this.mixer) return;
|
|
262
282
|
this.bind();
|
|
263
283
|
|
|
284
|
+
if (this._animator && this.director.isPlaying && this.director.weight > 0) this._animator.enabled = false;
|
|
285
|
+
|
|
264
286
|
this._totalOffsetPosition.set(0, 0, 0);
|
|
265
287
|
this._totalOffsetRotation.set(0, 0, 0, 1);
|
|
266
288
|
this._totalOffsetPosition2.set(0, 0, 0);
|
|
@@ -268,38 +290,60 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
268
290
|
let activeClips = 0;
|
|
269
291
|
let blend: number = 0;
|
|
270
292
|
let didPostExtrapolate = false;
|
|
293
|
+
let didPreExtrapolate = false;
|
|
271
294
|
for (let i = 0; i < this.clips.length; i++) {
|
|
272
295
|
const model = this.models[i];
|
|
273
296
|
const action = this.actions[i];
|
|
274
297
|
const clipModel = model.asset as Models.AnimationClipModel;
|
|
275
298
|
action.weight = 0;
|
|
299
|
+
|
|
276
300
|
const isInTimeRange = time >= model.start && time <= model.end;
|
|
301
|
+
const preExtrapolation: Models.ClipExtrapolation = model.preExtrapolationMode;
|
|
277
302
|
const postExtrapolation: Models.ClipExtrapolation = model.postExtrapolationMode;
|
|
303
|
+
const nextClip = i < this.clips.length - 1 ? this.models[i + 1] : null;
|
|
278
304
|
let isActive = isInTimeRange;
|
|
305
|
+
let doPreExtrapolate = false;
|
|
306
|
+
|
|
279
307
|
if (!isActive && !didPostExtrapolate && model.end < time && postExtrapolation !== Models.ClipExtrapolation.None) {
|
|
280
|
-
const nextClip = i < this.clips.length - 1 ? this.models[i + 1] : null;
|
|
281
308
|
// use post extrapolate if its the last clip of the next clip has not yet started
|
|
282
309
|
if (!nextClip || nextClip.start > time) {
|
|
283
310
|
isActive = true;
|
|
284
311
|
didPostExtrapolate = true;
|
|
285
312
|
}
|
|
286
313
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
314
|
+
else if (i == 0 && !isActive && !didPreExtrapolate && model.start > time && preExtrapolation !== Models.ClipExtrapolation.None) {
|
|
315
|
+
if (!nextClip || nextClip.start < time) {
|
|
316
|
+
isActive = true;
|
|
317
|
+
doPreExtrapolate = true;
|
|
318
|
+
didPreExtrapolate = true;
|
|
319
|
+
}
|
|
292
320
|
}
|
|
321
|
+
|
|
293
322
|
if (isActive) {
|
|
294
323
|
// const clip = this.clips[i];
|
|
295
324
|
let weight = 1;
|
|
296
325
|
weight *= this.evaluateWeight(time, i, this.models, isActive);
|
|
326
|
+
|
|
327
|
+
let handleLoop = isInTimeRange;
|
|
328
|
+
if(doPreExtrapolate){
|
|
329
|
+
if (preExtrapolation !== Models.ClipExtrapolation.Hold) {
|
|
330
|
+
time += model.start;
|
|
331
|
+
handleLoop = true;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
297
335
|
// TODO: handle clipIn again
|
|
298
336
|
let t = this.getClipTime(time, model);
|
|
299
337
|
let loops = 0;
|
|
300
338
|
const duration = clipModel.duration;
|
|
301
339
|
|
|
302
|
-
if (
|
|
340
|
+
if (doPreExtrapolate) {
|
|
341
|
+
if (preExtrapolation === Models.ClipExtrapolation.Hold) {
|
|
342
|
+
t = 0;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (handleLoop) {
|
|
303
347
|
if (clipModel.loop) {
|
|
304
348
|
// const t0 = t - .001;
|
|
305
349
|
loops += Math.floor(t / (duration + .000001));
|
|
@@ -468,6 +512,8 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
468
512
|
audioContextTimeOffset: Array<number> = [];
|
|
469
513
|
lastTime: number = 0;
|
|
470
514
|
|
|
515
|
+
private _audioLoader: THREE.AudioLoader | null = null;
|
|
516
|
+
|
|
471
517
|
private getAudioFilePath(path: string) {
|
|
472
518
|
// TODO: this should be the timeline asset location probably which MIGHT be different
|
|
473
519
|
const glbLocation = this.director.sourceId;
|
|
@@ -483,18 +529,9 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
483
529
|
}
|
|
484
530
|
|
|
485
531
|
addModel(model: Models.ClipModel) {
|
|
486
|
-
const path = this.getAudioFilePath(model.asset.clip);
|
|
487
532
|
const audio = new THREE.Audio(this.listener);
|
|
488
|
-
audio.
|
|
489
|
-
|
|
490
|
-
if (debug)
|
|
491
|
-
console.log(path, this.director.sourceId);
|
|
492
|
-
loader.load(path, (buffer) => {
|
|
493
|
-
audio.setBuffer(buffer);
|
|
494
|
-
audio.loop = model.asset.loop;
|
|
495
|
-
this.audio.push(audio);
|
|
496
|
-
this.models.push(model);
|
|
497
|
-
});
|
|
533
|
+
this.audio.push(audio);
|
|
534
|
+
this.models.push(model);
|
|
498
535
|
}
|
|
499
536
|
|
|
500
537
|
onDisable() {
|
|
@@ -521,13 +558,31 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
521
558
|
audio.stop();
|
|
522
559
|
}
|
|
523
560
|
}
|
|
561
|
+
|
|
524
562
|
evaluate(time: number) {
|
|
525
563
|
if (muteAudioTracks) return;
|
|
526
564
|
if (this.track.muted) return;
|
|
565
|
+
if (this.director.speed < 0) {
|
|
566
|
+
// Reversed audio playback is currently not supported
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const isMuted = this.director.context.application.muted;
|
|
570
|
+
// this is just so that we dont hear the very first beat when the audio starts but is muted
|
|
571
|
+
// if we dont add a delay we hear a little bit of the audio before it shuts down
|
|
572
|
+
// MAYBE instead of doing it like this we should connect a custom audio node (or disconnect the output node?)
|
|
573
|
+
const playTimeOffset = isMuted ? .1 : 0;
|
|
527
574
|
for (let i = 0; i < this.models.length; i++) {
|
|
528
575
|
const model = this.models[i];
|
|
529
576
|
const audio = this.audio[i];
|
|
530
|
-
|
|
577
|
+
// only trigger loading for tracks that are CLOSE to being played
|
|
578
|
+
if ((!audio || !audio.buffer) && this.isInTimeRange(model, time - 1, time + 1)) {
|
|
579
|
+
this.handleAudioLoading(model, audio);
|
|
580
|
+
}
|
|
581
|
+
if (AudioSource.userInteractionRegistered === false) continue;
|
|
582
|
+
if (audio === null || !audio.buffer) continue;
|
|
583
|
+
audio.playbackRate = this.director.context.time.timeScale;
|
|
584
|
+
audio.loop = model.asset.loop;
|
|
585
|
+
if (time >= model.start && time <= model.end && time < this.director.duration) {
|
|
531
586
|
if (this.director.isPlaying == false) {
|
|
532
587
|
if (audio.isPlaying)
|
|
533
588
|
audio.stop();
|
|
@@ -535,7 +590,7 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
535
590
|
}
|
|
536
591
|
else if (!audio.isPlaying) {
|
|
537
592
|
audio.offset = model.clipIn + (time - model.start) * model.timeScale;
|
|
538
|
-
audio.play();
|
|
593
|
+
audio.play(playTimeOffset);
|
|
539
594
|
}
|
|
540
595
|
else {
|
|
541
596
|
const targetOffset = model.clipIn + (time - model.start) * model.timeScale;
|
|
@@ -547,10 +602,11 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
547
602
|
if (diff > 0.3) {
|
|
548
603
|
audio.offset = targetOffset;
|
|
549
604
|
audio.stop();
|
|
550
|
-
audio.play();
|
|
605
|
+
audio.play(playTimeOffset);
|
|
551
606
|
}
|
|
552
607
|
}
|
|
553
|
-
let vol = model.asset.volume;
|
|
608
|
+
let vol = model.asset.volume as number;
|
|
609
|
+
if (isMuted) vol = 0;
|
|
554
610
|
if (model.easeInDuration > 0) {
|
|
555
611
|
const easeIn = Math.min((time - model.start) / model.easeInDuration, 1);
|
|
556
612
|
vol *= easeIn;
|
|
@@ -568,6 +624,60 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
568
624
|
}
|
|
569
625
|
this.lastTime = time;
|
|
570
626
|
}
|
|
627
|
+
|
|
628
|
+
/** Call to load audio buffer for a specific time in the track. Can be used to preload the timeline audio */
|
|
629
|
+
loadAudio(time: number, lookAhead: number = 0, lookBehind: number = 0) {
|
|
630
|
+
let promises: Array<Promise<AudioBuffer | null>> | null = null;
|
|
631
|
+
const rangeStart = time - lookBehind;
|
|
632
|
+
const rangeEnd = time + lookAhead;
|
|
633
|
+
for (const model of this.models) {
|
|
634
|
+
if (this.isInTimeRange(model, rangeStart, rangeEnd)) {
|
|
635
|
+
const audio = this.audio[this.models.indexOf(model)];
|
|
636
|
+
const promise = this.handleAudioLoading(model, audio);
|
|
637
|
+
if (promise !== null) {
|
|
638
|
+
if (promises === null) promises = [];
|
|
639
|
+
promises.push(promise);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (promises !== null) {
|
|
644
|
+
return Promise.all(promises);
|
|
645
|
+
}
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private isInTimeRange(model: Models.ClipModel, start: number, end: number) {
|
|
650
|
+
// Range surrounds clip range
|
|
651
|
+
if (start <= model.start && end >= model.end) return true;
|
|
652
|
+
// Range start is in clip range
|
|
653
|
+
if (start >= model.start && start <= model.end) return true;
|
|
654
|
+
// Range end is in clip range
|
|
655
|
+
if (end >= model.start && end <= model.end) return true;
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private handleAudioLoading(model: Models.ClipModel, audio: THREE.Audio): Promise<AudioBuffer | null> | null {
|
|
660
|
+
if (!this._audioLoader) {
|
|
661
|
+
const path = this.getAudioFilePath(model.asset.clip);
|
|
662
|
+
this._audioLoader = new THREE.AudioLoader();
|
|
663
|
+
// TODO: maybe we should cache the loaders / buffers here by path
|
|
664
|
+
if (debug) console.warn("LOAD audio track", path, this.director.sourceId);
|
|
665
|
+
const loadingPromise = new Promise<AudioBuffer | null>((resolve, _reject) => {
|
|
666
|
+
this._audioLoader!.load(path,
|
|
667
|
+
buffer => {
|
|
668
|
+
audio.setBuffer(buffer);
|
|
669
|
+
resolve(buffer);
|
|
670
|
+
},
|
|
671
|
+
undefined,
|
|
672
|
+
err => {
|
|
673
|
+
console.error("Error loading audio", err);
|
|
674
|
+
resolve(null);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
return loadingPromise;
|
|
678
|
+
}
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
571
681
|
}
|
|
572
682
|
|
|
573
683
|
export class SignalTrackHandler extends TrackHandler {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"useDefineForClassFields": true,
|
|
7
|
+
"lib": ["ESNext", "DOM"],
|
|
8
|
+
"moduleResolution": "Node",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"noUnusedLocals": false,
|
|
15
|
+
"noUnusedParameters": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noImplicitAny": false,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"jsx": "preserve",
|
|
20
|
+
"incremental": true,
|
|
21
|
+
"experimentalDecorators": true,
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"allowJs": true,
|
|
24
|
+
"types": [
|
|
25
|
+
"three",
|
|
26
|
+
"vite/client"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"include": [
|
|
30
|
+
"**/*.ts"
|
|
31
|
+
],
|
|
32
|
+
"exclude": ["node_modules", "dist"]
|
|
33
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const hasLicense = false;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|