@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.
- package/dist/EF_FRAMEGEN.js +0 -2
- package/dist/elements/EFAudio.d.ts +0 -1
- package/dist/elements/EFAudio.js +1 -5
- package/dist/elements/EFCaptions.js +1 -1
- package/dist/elements/EFImage.d.ts +2 -1
- package/dist/elements/EFImage.js +9 -3
- package/dist/elements/EFMedia.d.ts +8 -0
- package/dist/elements/EFMedia.js +247 -8
- package/dist/elements/EFTemporal.d.ts +7 -3
- package/dist/elements/EFTemporal.js +19 -1
- package/dist/elements/EFTimegroup.d.ts +1 -5
- package/dist/elements/EFTimegroup.js +5 -6
- package/dist/elements/EFWaveform.d.ts +16 -7
- package/dist/elements/EFWaveform.js +273 -163
- package/dist/elements/TargetController.d.ts +25 -0
- package/dist/elements/TargetController.js +164 -0
- package/dist/elements/TargetController.test.d.ts +19 -0
- package/dist/gui/EFPreview.d.ts +1 -1
- package/dist/gui/EFPreview.js +1 -0
- package/dist/gui/EFWorkbench.js +1 -1
- package/dist/gui/TWMixin.css.js +1 -1
- package/dist/style.css +3 -0
- package/package.json +10 -4
- package/src/elements/EFAudio.ts +1 -4
- package/src/elements/EFCaptions.ts +1 -1
- package/src/elements/EFImage.browsertest.ts +33 -2
- package/src/elements/EFImage.ts +10 -3
- package/src/elements/EFMedia.ts +304 -6
- package/src/elements/EFTemporal.ts +37 -5
- package/src/elements/EFTimegroup.ts +5 -7
- package/src/elements/EFWaveform.ts +341 -194
- package/src/elements/TargetController.test.ts +229 -0
- package/src/elements/TargetController.ts +219 -0
- package/src/gui/EFPreview.ts +10 -9
- package/src/gui/EFWorkbench.ts +1 -1
- package/types.json +1 -0
package/dist/EF_FRAMEGEN.js
CHANGED
|
@@ -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>;
|
package/dist/elements/EFAudio.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Task } from "@lit/task";
|
|
2
2
|
import { html } from "lit";
|
|
3
|
-
import {
|
|
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.
|
|
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
|
}
|
package/dist/elements/EFImage.js
CHANGED
|
@@ -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
|
|
28
|
-
|
|
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 {};
|
package/dist/elements/EFMedia.js
CHANGED
|
@@ -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
|
|
35
|
-
|
|
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.
|
|
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
|
-
],
|
|
663
|
+
], _EFMedia.prototype, "currentTimeMs", 2);
|
|
432
664
|
__decorateClass([
|
|
433
665
|
property({ type: String, attribute: "asset-id", reflect: true })
|
|
434
|
-
],
|
|
666
|
+
], _EFMedia.prototype, "assetId", 1);
|
|
435
667
|
__decorateClass([
|
|
436
668
|
state()
|
|
437
|
-
],
|
|
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
|
-
* `
|
|
138
|
+
* `currentSourceTimeMs` will be 10s.
|
|
135
139
|
*
|
|
136
140
|
* sourcein=10s sourceout=10s
|
|
137
141
|
* / / /
|
|
138
142
|
* |--------|=================|---------|
|
|
139
143
|
* ^
|
|
140
144
|
* |_
|
|
141
|
-
*
|
|
145
|
+
* currentSourceTimeMs === 10s
|
|
142
146
|
* |_
|
|
143
147
|
* ownCurrentTimeMs === 0s
|
|
144
148
|
*/
|
|
145
|
-
get
|
|
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
|
|
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 = "
|
|
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
|
-
|
|
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:
|
|
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" | "
|
|
16
|
+
mode: "roundBars" | "bars" | "bricks" | "line" | "curve" | "pixel" | "wave" | "spikes";
|
|
15
17
|
color: string;
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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 {};
|