@editframe/elements 0.14.0-beta.3 → 0.15.0-beta.10

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.
Files changed (36) hide show
  1. package/dist/EF_FRAMEGEN.js +0 -2
  2. package/dist/elements/EFAudio.d.ts +0 -1
  3. package/dist/elements/EFAudio.js +1 -5
  4. package/dist/elements/EFCaptions.js +1 -1
  5. package/dist/elements/EFImage.d.ts +2 -1
  6. package/dist/elements/EFImage.js +9 -3
  7. package/dist/elements/EFMedia.d.ts +8 -0
  8. package/dist/elements/EFMedia.js +247 -8
  9. package/dist/elements/EFTemporal.d.ts +7 -3
  10. package/dist/elements/EFTemporal.js +19 -1
  11. package/dist/elements/EFTimegroup.d.ts +1 -5
  12. package/dist/elements/EFTimegroup.js +5 -6
  13. package/dist/elements/EFWaveform.d.ts +16 -7
  14. package/dist/elements/EFWaveform.js +273 -163
  15. package/dist/elements/TargetController.d.ts +25 -0
  16. package/dist/elements/TargetController.js +164 -0
  17. package/dist/elements/TargetController.test.d.ts +19 -0
  18. package/dist/gui/EFPreview.d.ts +1 -1
  19. package/dist/gui/EFPreview.js +1 -0
  20. package/dist/gui/EFWorkbench.js +1 -1
  21. package/dist/gui/TWMixin.css.js +1 -1
  22. package/dist/style.css +3 -0
  23. package/package.json +10 -4
  24. package/src/elements/EFAudio.ts +1 -4
  25. package/src/elements/EFCaptions.ts +1 -1
  26. package/src/elements/EFImage.browsertest.ts +33 -2
  27. package/src/elements/EFImage.ts +10 -3
  28. package/src/elements/EFMedia.ts +304 -6
  29. package/src/elements/EFTemporal.ts +37 -5
  30. package/src/elements/EFTimegroup.ts +5 -7
  31. package/src/elements/EFWaveform.ts +341 -194
  32. package/src/elements/TargetController.test.ts +229 -0
  33. package/src/elements/TargetController.ts +219 -0
  34. package/src/gui/EFPreview.ts +10 -9
  35. package/src/gui/EFWorkbench.ts +1 -1
  36. package/types.json +1 -0
@@ -104,8 +104,6 @@ class EfFramegen {
104
104
  this.audioBufferPromise = firstGroup.renderAudio(
105
105
  renderOptions.encoderOptions.alignedFromUs / 1e3,
106
106
  renderOptions.encoderOptions.alignedToUs / 1e3
107
- // renderOptions.encoderOptions.fromMs,
108
- // renderOptions.encoderOptions.toMs,
109
107
  );
110
108
  console.log("Initialized");
111
109
  }
@@ -2,7 +2,6 @@ import { Task } from '@lit/task';
2
2
  import { EFMedia } from './EFMedia.js';
3
3
  export declare class EFAudio extends EFMedia {
4
4
  audioElementRef: import('lit-html/directives/ref.js').Ref<HTMLAudioElement>;
5
- src: string;
6
5
  render(): import('lit-html').TemplateResult<1>;
7
6
  get audioElement(): HTMLAudioElement | undefined;
8
7
  frameTask: Task<readonly [import('@lit/task').TaskStatus, import('@lit/task').TaskStatus, import('@lit/task').TaskStatus, import('@lit/task').TaskStatus, import('@lit/task').TaskStatus], void>;
@@ -1,6 +1,6 @@
1
1
  import { Task } from "@lit/task";
2
2
  import { html } from "lit";
3
- import { property, customElement } from "lit/decorators.js";
3
+ import { customElement } from "lit/decorators.js";
4
4
  import { createRef, ref } from "lit/directives/ref.js";
5
5
  import { EFMedia } from "./EFMedia.js";
6
6
  var __defProp = Object.defineProperty;
@@ -17,7 +17,6 @@ let EFAudio = class extends EFMedia {
17
17
  constructor() {
18
18
  super(...arguments);
19
19
  this.audioElementRef = createRef();
20
- this.src = "";
21
20
  this.frameTask = new Task(this, {
22
21
  args: () => [
23
22
  this.trackFragmentIndexLoader.status,
@@ -43,9 +42,6 @@ let EFAudio = class extends EFMedia {
43
42
  return this.audioElementRef.value;
44
43
  }
45
44
  };
46
- __decorateClass([
47
- property({ type: String })
48
- ], EFAudio.prototype, "src", 2);
49
45
  EFAudio = __decorateClass([
50
46
  customElement("ef-audio")
51
47
  ], EFAudio);
@@ -335,7 +335,7 @@ let EFCaptions = class extends EFSourceMixin(
335
335
  if (!transcriptionFragment) {
336
336
  return;
337
337
  }
338
- const currentTimeMs = this.targetElement.trimAdjustedOwnCurrentTimeMs;
338
+ const currentTimeMs = this.targetElement.currentSourceTimeMs;
339
339
  const currentTimeSec = currentTimeMs / 1e3;
340
340
  const currentWord = transcriptionFragment.word_segments.find(
341
341
  (word) => currentTimeSec >= word.start && currentTimeSec <= word.end
@@ -1,6 +1,6 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement } from 'lit';
3
- declare const EFImage_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
3
+ declare const EFImage_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
4
4
  export declare class EFImage extends EFImage_base {
5
5
  #private;
6
6
  static styles: import('lit').CSSResult[];
@@ -10,6 +10,7 @@ export declare class EFImage extends EFImage_base {
10
10
  get assetId(): string | null;
11
11
  render(): import('lit-html').TemplateResult<1>;
12
12
  assetPath(): string;
13
+ get hasOwnDuration(): boolean;
13
14
  fetchImage: Task<readonly [string, typeof fetch], void>;
14
15
  frameTask: Task<readonly [import('@lit/task').TaskStatus], void>;
15
16
  }
@@ -5,6 +5,7 @@ import { createRef, ref } from "lit/directives/ref.js";
5
5
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
6
6
  import { EF_RENDERING } from "../EF_RENDERING.js";
7
7
  import { EFSourceMixin } from "./EFSourceMixin.js";
8
+ import { EFTemporal } from "./EFTemporal.js";
8
9
  import { FetchMixin } from "./FetchMixin.js";
9
10
  var __defProp = Object.defineProperty;
10
11
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -24,9 +25,11 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
24
25
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
25
26
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
26
27
  var _assetId;
27
- let EFImage = class extends EFSourceMixin(FetchMixin(LitElement), {
28
- assetType: "image_files"
29
- }) {
28
+ let EFImage = class extends EFTemporal(
29
+ EFSourceMixin(FetchMixin(LitElement), {
30
+ assetType: "image_files"
31
+ })
32
+ ) {
30
33
  constructor() {
31
34
  super(...arguments);
32
35
  this.imageRef = createRef();
@@ -76,6 +79,9 @@ let EFImage = class extends EFSourceMixin(FetchMixin(LitElement), {
76
79
  }
77
80
  return `/@ef-image/${this.src}`;
78
81
  }
82
+ get hasOwnDuration() {
83
+ return this.hasExplicitDuration;
84
+ }
79
85
  };
80
86
  _assetId = /* @__PURE__ */ new WeakMap();
81
87
  EFImage.styles = [
@@ -64,5 +64,13 @@ export declare class EFMedia extends EFMedia_base {
64
64
  startMs: number;
65
65
  endMs: number;
66
66
  } | undefined>;
67
+ fftSize: number;
68
+ fftDecay: number;
69
+ private static readonly MIN_DB;
70
+ private static readonly MAX_DB;
71
+ private static readonly DECAY_WEIGHT;
72
+ get FREQ_WEIGHTS(): Float32Array;
73
+ byteTimeDomainTask: Task<readonly [import('@lit/task').TaskStatus, number, number, number], Uint8Array | null>;
74
+ frequencyDataTask: Task<readonly [import('@lit/task').TaskStatus, number, number, number], Uint8Array | null>;
67
75
  }
68
76
  export {};
@@ -10,6 +10,7 @@ import { EF_RENDERING } from "../EF_RENDERING.js";
10
10
  import { EFSourceMixin } from "./EFSourceMixin.js";
11
11
  import { EFTemporal, isEFTemporal } from "./EFTemporal.js";
12
12
  import { FetchMixin } from "./FetchMixin.js";
13
+ import { EFTargetable } from "./TargetController.js";
13
14
  var __defProp = Object.defineProperty;
14
15
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
16
  var __decorateClass = (decorators, target, key, kind) => {
@@ -21,6 +22,32 @@ var __decorateClass = (decorators, target, key, kind) => {
21
22
  return result;
22
23
  };
23
24
  const log = debug("ef:elements:EFMedia");
25
+ const freqWeightsCache = /* @__PURE__ */ new Map();
26
+ class LRUCache {
27
+ constructor(maxSize) {
28
+ this.cache = /* @__PURE__ */ new Map();
29
+ this.maxSize = maxSize;
30
+ }
31
+ get(key) {
32
+ const value = this.cache.get(key);
33
+ if (value) {
34
+ this.cache.delete(key);
35
+ this.cache.set(key, value);
36
+ }
37
+ return value;
38
+ }
39
+ set(key, value) {
40
+ if (this.cache.has(key)) {
41
+ this.cache.delete(key);
42
+ } else if (this.cache.size >= this.maxSize) {
43
+ const firstKey = this.cache.keys().next().value;
44
+ if (firstKey) {
45
+ this.cache.delete(firstKey);
46
+ }
47
+ }
48
+ this.cache.set(key, value);
49
+ }
50
+ }
24
51
  const deepGetMediaElements = (element, medias = []) => {
25
52
  for (const child of Array.from(element.children)) {
26
53
  if (child instanceof EFMedia) {
@@ -31,9 +58,11 @@ const deepGetMediaElements = (element, medias = []) => {
31
58
  }
32
59
  return medias;
33
60
  };
34
- class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
35
- assetType: "isobmff_files"
36
- }) {
61
+ const _EFMedia = class _EFMedia2 extends EFTargetable(
62
+ EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
63
+ assetType: "isobmff_files"
64
+ })
65
+ ) {
37
66
  constructor() {
38
67
  super(...arguments);
39
68
  this.currentTimeMs = 0;
@@ -213,6 +242,180 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
213
242
  };
214
243
  }
215
244
  });
245
+ this.fftSize = 512;
246
+ this.fftDecay = 8;
247
+ this.#byteTimeDomainCache = new LRUCache(100);
248
+ this.byteTimeDomainTask = new Task(this, {
249
+ autoRun: EF_INTERACTIVE,
250
+ args: () => [
251
+ this.audioBufferTask.status,
252
+ this.currentSourceTimeMs,
253
+ this.fftSize,
254
+ this.fftDecay
255
+ ],
256
+ task: async () => {
257
+ await this.audioBufferTask.taskComplete;
258
+ if (!this.audioBufferTask.value) return null;
259
+ if (this.currentSourceTimeMs <= 0) return null;
260
+ const currentTimeMs = this.currentSourceTimeMs;
261
+ const startOffsetMs = this.audioBufferTask.value.startOffsetMs;
262
+ const audioBuffer = this.audioBufferTask.value.buffer;
263
+ const smoothedKey = `${this.fftSize}:${this.fftDecay}:${startOffsetMs}:${currentTimeMs}`;
264
+ const cachedSmoothedData = this.#byteTimeDomainCache.get(smoothedKey);
265
+ if (cachedSmoothedData) {
266
+ return cachedSmoothedData;
267
+ }
268
+ const framesData = await Promise.all(
269
+ Array.from({ length: this.fftDecay }, async (_, i) => {
270
+ const frameOffset = i * (1e3 / 30);
271
+ const startTime = Math.max(
272
+ 0,
273
+ (currentTimeMs - frameOffset - startOffsetMs) / 1e3
274
+ );
275
+ const cacheKey = `${this.fftSize}:${startOffsetMs}:${startTime}`;
276
+ const cachedFrame = this.#byteTimeDomainCache.get(cacheKey);
277
+ if (cachedFrame) {
278
+ return cachedFrame;
279
+ }
280
+ const audioContext = new OfflineAudioContext(
281
+ 2,
282
+ 48e3 * (1 / 30),
283
+ 48e3
284
+ );
285
+ const analyser = audioContext.createAnalyser();
286
+ analyser.fftSize = this.fftSize;
287
+ const gainNode = audioContext.createGain();
288
+ gainNode.gain.value = 10;
289
+ analyser.smoothingTimeConstant = 0.4;
290
+ analyser.minDecibels = -90;
291
+ analyser.maxDecibels = -10;
292
+ const audioBufferSource = audioContext.createBufferSource();
293
+ audioBufferSource.buffer = audioBuffer;
294
+ const filter = audioContext.createBiquadFilter();
295
+ filter.type = "bandpass";
296
+ filter.frequency.value = 1e3;
297
+ filter.Q.value = 0.5;
298
+ audioBufferSource.connect(gainNode);
299
+ gainNode.connect(filter);
300
+ filter.connect(analyser);
301
+ analyser.connect(audioContext.destination);
302
+ audioBufferSource.start(0, startTime, 1 / 30);
303
+ try {
304
+ await audioContext.startRendering();
305
+ const frameData = new Uint8Array(analyser.fftSize);
306
+ analyser.getByteTimeDomainData(frameData);
307
+ this.#byteTimeDomainCache.set(cacheKey, frameData);
308
+ return frameData;
309
+ } finally {
310
+ audioBufferSource.disconnect();
311
+ analyser.disconnect();
312
+ }
313
+ })
314
+ );
315
+ const frameLength = framesData[0]?.length ?? 0;
316
+ const smoothedData = new Uint8Array(frameLength);
317
+ for (let i = 0; i < frameLength; i++) {
318
+ let weightedSum = 0;
319
+ let weightSum = 0;
320
+ framesData.forEach((frame, frameIndex) => {
321
+ const decayWeight = _EFMedia2.DECAY_WEIGHT ** frameIndex;
322
+ weightedSum += frame[i] * decayWeight;
323
+ weightSum += decayWeight;
324
+ });
325
+ smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
326
+ }
327
+ this.#byteTimeDomainCache.set(
328
+ smoothedKey,
329
+ smoothedData.slice(0, Math.floor(smoothedData.length * 0.8))
330
+ );
331
+ return smoothedData;
332
+ }
333
+ });
334
+ this.#frequencyDataCache = new LRUCache(100);
335
+ this.frequencyDataTask = new Task(this, {
336
+ autoRun: EF_INTERACTIVE,
337
+ args: () => [
338
+ this.audioBufferTask.status,
339
+ this.currentSourceTimeMs,
340
+ this.fftSize,
341
+ // Add fftSize to dependency array
342
+ this.fftDecay
343
+ // Add fftDecay to dependency array
344
+ ],
345
+ task: async () => {
346
+ await this.audioBufferTask.taskComplete;
347
+ if (!this.audioBufferTask.value) return null;
348
+ if (this.currentSourceTimeMs <= 0) return null;
349
+ const currentTimeMs = this.currentSourceTimeMs;
350
+ const startOffsetMs = this.audioBufferTask.value.startOffsetMs;
351
+ const audioBuffer = this.audioBufferTask.value.buffer;
352
+ const smoothedKey = `${this.fftSize}:${this.fftDecay}:${startOffsetMs}:${currentTimeMs}`;
353
+ const cachedSmoothedData = this.#frequencyDataCache.get(smoothedKey);
354
+ if (cachedSmoothedData) {
355
+ return cachedSmoothedData;
356
+ }
357
+ const framesData = await Promise.all(
358
+ Array.from({ length: this.fftDecay }, async (_, i) => {
359
+ const frameOffset = i * (1e3 / 30);
360
+ const startTime = Math.max(
361
+ 0,
362
+ (currentTimeMs - frameOffset - startOffsetMs) / 1e3
363
+ );
364
+ const cacheKey = `${this.fftSize}:${startOffsetMs}:${startTime}`;
365
+ const cachedFrame = this.#frequencyDataCache.get(cacheKey);
366
+ if (cachedFrame) {
367
+ return cachedFrame;
368
+ }
369
+ const audioContext = new OfflineAudioContext(
370
+ 2,
371
+ 48e3 * (1 / 30),
372
+ 48e3
373
+ );
374
+ const analyser = audioContext.createAnalyser();
375
+ analyser.fftSize = this.fftSize;
376
+ analyser.minDecibels = _EFMedia2.MIN_DB;
377
+ analyser.maxDecibels = _EFMedia2.MAX_DB;
378
+ const audioBufferSource = audioContext.createBufferSource();
379
+ audioBufferSource.buffer = audioBuffer;
380
+ audioBufferSource.connect(analyser);
381
+ analyser.connect(audioContext.destination);
382
+ audioBufferSource.start(0, startTime, 1 / 30);
383
+ try {
384
+ await audioContext.startRendering();
385
+ const frameData = new Uint8Array(this.fftSize / 2);
386
+ analyser.getByteFrequencyData(frameData);
387
+ this.#frequencyDataCache.set(cacheKey, frameData);
388
+ return frameData;
389
+ } finally {
390
+ audioBufferSource.disconnect();
391
+ analyser.disconnect();
392
+ }
393
+ })
394
+ );
395
+ const frameLength = framesData[0]?.length ?? 0;
396
+ const smoothedData = new Uint8Array(frameLength);
397
+ for (let i = 0; i < frameLength; i++) {
398
+ let weightedSum = 0;
399
+ let weightSum = 0;
400
+ framesData.forEach((frame, frameIndex) => {
401
+ const decayWeight = _EFMedia2.DECAY_WEIGHT ** frameIndex;
402
+ weightedSum += frame[i] * decayWeight;
403
+ weightSum += decayWeight;
404
+ });
405
+ smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
406
+ }
407
+ smoothedData.forEach((value, i) => {
408
+ const freqWeight = this.FREQ_WEIGHTS[i];
409
+ smoothedData[i] = Math.min(255, Math.round(value * freqWeight));
410
+ });
411
+ const slicedData = smoothedData.slice(
412
+ 0,
413
+ Math.floor(smoothedData.length / 2)
414
+ );
415
+ this.#frequencyDataCache.set(smoothedKey, slicedData);
416
+ return slicedData;
417
+ }
418
+ });
216
419
  }
217
420
  static {
218
421
  this.styles = [
@@ -265,7 +468,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
265
468
  }
266
469
  updated(changedProperties) {
267
470
  if (changedProperties.has("ownCurrentTimeMs")) {
268
- this.executeSeek(this.trimAdjustedOwnCurrentTimeMs);
471
+ this.executeSeek(this.currentSourceTimeMs);
269
472
  }
270
473
  if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
271
474
  const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
@@ -425,16 +628,52 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
425
628
  endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3 - this.trimEndMs
426
629
  };
427
630
  }
428
- }
631
+ static {
632
+ this.MIN_DB = -90;
633
+ }
634
+ static {
635
+ this.MAX_DB = -20;
636
+ }
637
+ static {
638
+ this.DECAY_WEIGHT = 0.7;
639
+ }
640
+ // Update FREQ_WEIGHTS to use the instance fftSize instead of a static value
641
+ get FREQ_WEIGHTS() {
642
+ if (freqWeightsCache.has(this.fftSize)) {
643
+ return freqWeightsCache.get(this.fftSize);
644
+ }
645
+ const weights = new Float32Array(this.fftSize / 2).map((_, i) => {
646
+ const frequency = i * 48e3 / this.fftSize;
647
+ if (frequency < 60) return 0.3;
648
+ if (frequency < 250) return 0.4;
649
+ if (frequency < 500) return 0.6;
650
+ if (frequency < 2e3) return 0.8;
651
+ if (frequency < 4e3) return 1.2;
652
+ if (frequency < 8e3) return 1.6;
653
+ return 2;
654
+ });
655
+ freqWeightsCache.set(this.fftSize, weights);
656
+ return weights;
657
+ }
658
+ #byteTimeDomainCache;
659
+ #frequencyDataCache;
660
+ };
429
661
  __decorateClass([
430
662
  property({ type: Number })
431
- ], EFMedia.prototype, "currentTimeMs", 2);
663
+ ], _EFMedia.prototype, "currentTimeMs", 2);
432
664
  __decorateClass([
433
665
  property({ type: String, attribute: "asset-id", reflect: true })
434
- ], EFMedia.prototype, "assetId", 1);
666
+ ], _EFMedia.prototype, "assetId", 1);
435
667
  __decorateClass([
436
668
  state()
437
- ], EFMedia.prototype, "desiredSeekTimeMs", 2);
669
+ ], _EFMedia.prototype, "desiredSeekTimeMs", 2);
670
+ __decorateClass([
671
+ property({ type: Number })
672
+ ], _EFMedia.prototype, "fftSize", 2);
673
+ __decorateClass([
674
+ property({ type: Number })
675
+ ], _EFMedia.prototype, "fftDecay", 2);
676
+ let EFMedia = _EFMedia;
438
677
  export {
439
678
  EFMedia,
440
679
  deepGetMediaElements
@@ -6,6 +6,10 @@ export declare const timegroupContext: {
6
6
  };
7
7
  export declare class TemporalMixinInterface {
8
8
  get hasOwnDuration(): boolean;
9
+ /**
10
+ * Whether the element has a duration set as an attribute.
11
+ */
12
+ get hasExplicitDuration(): boolean;
9
13
  /**
10
14
  * Used to trim the start of the media.
11
15
  *
@@ -131,18 +135,18 @@ export declare class TemporalMixinInterface {
131
135
  * elements.
132
136
  *
133
137
  * For example, if the media has a `sourcein` value of 10s, when `ownCurrentTimeMs` is 0s,
134
- * `trimAdjustedOwnCurrentTimeMs` will be 10s.
138
+ * `currentSourceTimeMs` will be 10s.
135
139
  *
136
140
  * sourcein=10s sourceout=10s
137
141
  * / / /
138
142
  * |--------|=================|---------|
139
143
  * ^
140
144
  * |_
141
- * trimAdjustedOwnCurrentTimeMs === 10s
145
+ * currentSourceTimeMs === 10s
142
146
  * |_
143
147
  * ownCurrentTimeMs === 0s
144
148
  */
145
- get trimAdjustedOwnCurrentTimeMs(): number;
149
+ get currentSourceTimeMs(): number;
146
150
  set duration(value: string);
147
151
  get duration(): string;
148
152
  /**
@@ -198,6 +198,9 @@ const EFTemporal = (superClass) => {
198
198
  }
199
199
  return parent;
200
200
  }
201
+ get hasExplicitDuration() {
202
+ return this._durationMs !== void 0;
203
+ }
201
204
  get hasOwnDuration() {
202
205
  return false;
203
206
  }
@@ -275,6 +278,10 @@ const EFTemporal = (superClass) => {
275
278
  get endTimeMs() {
276
279
  return this.startTimeMs + this.durationMs;
277
280
  }
281
+ /**
282
+ * The current time of the element within itself.
283
+ * Compare with `currentTimeMs` to see the current time with respect to the root timegroup
284
+ */
278
285
  get ownCurrentTimeMs() {
279
286
  if (this.rootTimegroup) {
280
287
  return Math.min(
@@ -288,7 +295,7 @@ const EFTemporal = (superClass) => {
288
295
  * Used to calculate the internal currentTimeMs of the element. This is useful
289
296
  * for mapping to internal media time codes for audio/video elements.
290
297
  */
291
- get trimAdjustedOwnCurrentTimeMs() {
298
+ get currentSourceTimeMs() {
292
299
  if (this.rootTimegroup) {
293
300
  if (this.sourceInMs && this.sourceOutMs) {
294
301
  return Math.min(
@@ -309,6 +316,17 @@ const EFTemporal = (superClass) => {
309
316
  }
310
317
  return 0;
311
318
  }
319
+ updated(changedProperties) {
320
+ super.updated(changedProperties);
321
+ if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
322
+ const timelineTimeMs = (this.rootTimegroup ?? this).ownCurrentTimeMs;
323
+ if (this.startTimeMs > timelineTimeMs || this.endTimeMs < timelineTimeMs) {
324
+ this.style.display = "none";
325
+ return;
326
+ }
327
+ this.style.display = "";
328
+ }
329
+ }
312
330
  }
313
331
  __decorateClass([
314
332
  consume({ context: timegroupContext, subscribe: true }),
@@ -27,11 +27,7 @@ export declare class EFTimegroup extends EFTimegroup_base {
27
27
  * that caused issues with constructing audio data. We had negative durations
28
28
  * in calculations and it was not clear why.
29
29
  */
30
- waitForMediaDurations(): Promise<({
31
- trackId: string;
32
- buffer: import('mp4box').MP4ArrayBuffer;
33
- mp4File: import('../../../assets/src/MP4File.ts').MP4File;
34
- }[] | undefined)[]>;
30
+ waitForMediaDurations(): Promise<Record<number, import('../../../assets/src/index.ts').TrackFragmentIndex>[]>;
35
31
  get childTemporals(): import('./EFTemporal.js').TemporalMixinInterface[];
36
32
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
37
33
  private updateAnimations;
@@ -45,7 +45,7 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
45
45
  __privateAdd(this, _EFTimegroup_instances);
46
46
  this._timeGroupContext = this;
47
47
  __privateAdd(this, _currentTime, 0);
48
- this.mode = "sequence";
48
+ this.mode = "contain";
49
49
  this.overlapMs = 0;
50
50
  this.fit = "none";
51
51
  __privateAdd(this, _resizeObserver);
@@ -186,10 +186,9 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
186
186
  * in calculations and it was not clear why.
187
187
  */
188
188
  async waitForMediaDurations() {
189
+ const mediaElements = deepGetMediaElements(this);
189
190
  return await Promise.all(
190
- deepGetMediaElements(this).map(
191
- (media) => media.initSegmentsLoader.taskComplete
192
- )
191
+ mediaElements.map((m) => m.trackFragmentIndexLoader.taskComplete)
193
192
  );
194
193
  }
195
194
  get childTemporals() {
@@ -378,7 +377,7 @@ EFTimegroup.styles = css`
378
377
  display: block;
379
378
  width: 100%;
380
379
  height: 100%;
381
- position: relative;
380
+ position: absolute;
382
381
  transform-origin: center center;
383
382
  }
384
383
  `;
@@ -402,7 +401,7 @@ __decorateClass([
402
401
  property({ type: String })
403
402
  ], EFTimegroup.prototype, "fit", 2);
404
403
  __decorateClass([
405
- property({ type: Number })
404
+ property({ type: Number, attribute: "currenttime" })
406
405
  ], EFTimegroup.prototype, "currentTime", 1);
407
406
  EFTimegroup = __decorateClass([
408
407
  customElement("ef-timegroup")
@@ -1,35 +1,44 @@
1
- import { EFAudio } from './EFAudio.js';
2
1
  import { Task } from '@lit/task';
3
2
  import { LitElement, PropertyValueMap } from 'lit';
4
3
  import { Ref } from 'lit/directives/ref.js';
4
+ import { EFAudio } from './EFAudio.js';
5
5
  import { EFVideo } from './EFVideo.js';
6
+ import { TargetController } from './TargetController.ts';
6
7
  declare const EFWaveform_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
7
8
  export declare class EFWaveform extends EFWaveform_base {
8
9
  static styles: import('lit').CSSResult;
9
10
  canvasRef: Ref<HTMLCanvasElement>;
10
11
  private ctx;
12
+ private styleObserver;
11
13
  private resizeObserver?;
12
14
  private mutationObserver?;
13
15
  render(): import('lit-html').TemplateResult<1>;
14
- mode: "roundBars" | "bars" | "bricks" | "equalizer" | "curve" | "line" | "pixel" | "wave";
16
+ mode: "roundBars" | "bars" | "bricks" | "line" | "curve" | "pixel" | "wave" | "spikes";
15
17
  color: string;
16
- targetSelector: string;
17
- set target(value: string);
18
+ target: string;
19
+ targetElement: EFAudio | EFVideo | null;
20
+ lineWidth: number;
21
+ targetController: TargetController;
18
22
  connectedCallback(): void;
19
23
  disconnectedCallback(): void;
20
24
  private resizeCanvas;
21
25
  protected initCanvas(): CanvasRenderingContext2D | null;
22
26
  protected drawBars(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
23
27
  protected drawBricks(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
24
- protected drawLine(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
25
28
  protected drawRoundBars(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
26
29
  protected drawEqualizer(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
30
+ protected drawLine(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
27
31
  protected drawCurve(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
28
32
  protected drawPixel(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
29
33
  protected drawWave(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
30
- frameTask: Task<readonly [import('@lit/task').TaskStatus], void>;
34
+ protected drawSpikes(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
35
+ frameTask: Task<readonly [EFAudio | EFVideo | null, Uint8Array | null | undefined], void>;
31
36
  get durationMs(): number;
32
- get targetElement(): EFAudio | EFVideo;
33
37
  protected updated(changedProperties: PropertyValueMap<this>): void;
34
38
  }
39
+ declare global {
40
+ interface HTMLElementTagNameMap {
41
+ "ef-waveform": EFWaveform & Element;
42
+ }
43
+ }
35
44
  export {};