@dawcore/components 0.0.16 → 0.0.17
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/index.d.mts +136 -3
- package/dist/index.d.ts +136 -3
- package/dist/index.js +474 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +473 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ __export(index_exports, {
|
|
|
51
51
|
DawRecordButtonElement: () => DawRecordButtonElement,
|
|
52
52
|
DawRulerElement: () => DawRulerElement,
|
|
53
53
|
DawSelectionElement: () => DawSelectionElement,
|
|
54
|
+
DawSpectrogramElement: () => DawSpectrogramElement,
|
|
54
55
|
DawStopButtonElement: () => DawStopButtonElement,
|
|
55
56
|
DawTrackControlsElement: () => DawTrackControlsElement,
|
|
56
57
|
DawTrackElement: () => DawTrackElement,
|
|
@@ -58,6 +59,7 @@ __export(index_exports, {
|
|
|
58
59
|
DawTransportElement: () => DawTransportElement,
|
|
59
60
|
DawWaveformElement: () => DawWaveformElement,
|
|
60
61
|
RecordingController: () => RecordingController,
|
|
62
|
+
SpectrogramController: () => SpectrogramController,
|
|
61
63
|
isDomClip: () => isDomClip,
|
|
62
64
|
splitAtPlayhead: () => splitAtPlayhead
|
|
63
65
|
});
|
|
@@ -229,6 +231,7 @@ var DawTrackElement = class extends import_lit2.LitElement {
|
|
|
229
231
|
this.muted = false;
|
|
230
232
|
this.soloed = false;
|
|
231
233
|
this.renderMode = "waveform";
|
|
234
|
+
this.spectrogramConfig = null;
|
|
232
235
|
this.trackId = crypto.randomUUID();
|
|
233
236
|
// Track removal is detected by the editor's MutationObserver,
|
|
234
237
|
// not by dispatching from disconnectedCallback (detached elements
|
|
@@ -256,7 +259,16 @@ var DawTrackElement = class extends import_lit2.LitElement {
|
|
|
256
259
|
this._hasRendered = true;
|
|
257
260
|
return;
|
|
258
261
|
}
|
|
259
|
-
const trackProps = [
|
|
262
|
+
const trackProps = [
|
|
263
|
+
"volume",
|
|
264
|
+
"pan",
|
|
265
|
+
"muted",
|
|
266
|
+
"soloed",
|
|
267
|
+
"src",
|
|
268
|
+
"name",
|
|
269
|
+
"renderMode",
|
|
270
|
+
"spectrogramConfig"
|
|
271
|
+
];
|
|
260
272
|
const hasTrackChange = trackProps.some((p) => changed.has(p));
|
|
261
273
|
if (hasTrackChange) {
|
|
262
274
|
this.dispatchEvent(
|
|
@@ -290,6 +302,9 @@ __decorateClass([
|
|
|
290
302
|
__decorateClass([
|
|
291
303
|
(0, import_decorators2.property)({ attribute: "render-mode" })
|
|
292
304
|
], DawTrackElement.prototype, "renderMode", 2);
|
|
305
|
+
__decorateClass([
|
|
306
|
+
(0, import_decorators2.property)({ attribute: false })
|
|
307
|
+
], DawTrackElement.prototype, "spectrogramConfig", 2);
|
|
293
308
|
DawTrackElement = __decorateClass([
|
|
294
309
|
(0, import_decorators2.customElement)("daw-track")
|
|
295
310
|
], DawTrackElement);
|
|
@@ -2757,6 +2772,121 @@ var RecordingController = class {
|
|
|
2757
2772
|
}
|
|
2758
2773
|
};
|
|
2759
2774
|
|
|
2775
|
+
// src/controllers/spectrogram-controller.ts
|
|
2776
|
+
var import_spectrogram = require("@dawcore/spectrogram");
|
|
2777
|
+
var LIBRARY_DEFAULTS = {
|
|
2778
|
+
fftSize: 2048,
|
|
2779
|
+
windowFunction: "hann",
|
|
2780
|
+
frequencyScale: "mel",
|
|
2781
|
+
minFrequency: 0,
|
|
2782
|
+
gainDb: 20,
|
|
2783
|
+
rangeDb: 80
|
|
2784
|
+
};
|
|
2785
|
+
var LIBRARY_DEFAULT_COLOR_MAP = "viridis";
|
|
2786
|
+
var SpectrogramController = class {
|
|
2787
|
+
constructor(host, workerFactory) {
|
|
2788
|
+
this.orchestrator = null;
|
|
2789
|
+
this.editorConfig = null;
|
|
2790
|
+
this.editorColorMap = null;
|
|
2791
|
+
this.trackConfigs = /* @__PURE__ */ new Map();
|
|
2792
|
+
this.trackColorMaps = /* @__PURE__ */ new Map();
|
|
2793
|
+
this.host = host;
|
|
2794
|
+
this.workerFactory = workerFactory;
|
|
2795
|
+
this.host.addController(this);
|
|
2796
|
+
}
|
|
2797
|
+
hostConnected() {
|
|
2798
|
+
}
|
|
2799
|
+
hostDisconnected() {
|
|
2800
|
+
this.dispose();
|
|
2801
|
+
}
|
|
2802
|
+
setEditorConfig(config) {
|
|
2803
|
+
this.editorConfig = config;
|
|
2804
|
+
this.reapply();
|
|
2805
|
+
}
|
|
2806
|
+
setEditorColorMap(colorMap) {
|
|
2807
|
+
this.editorColorMap = colorMap;
|
|
2808
|
+
this.reapply();
|
|
2809
|
+
}
|
|
2810
|
+
setTrackConfig(trackId, config) {
|
|
2811
|
+
if (config === null) {
|
|
2812
|
+
this.trackConfigs.delete(trackId);
|
|
2813
|
+
} else {
|
|
2814
|
+
this.trackConfigs.set(trackId, config);
|
|
2815
|
+
}
|
|
2816
|
+
this.reapply();
|
|
2817
|
+
}
|
|
2818
|
+
setTrackColorMap(trackId, colorMap) {
|
|
2819
|
+
if (colorMap === null) {
|
|
2820
|
+
this.trackColorMaps.delete(trackId);
|
|
2821
|
+
} else {
|
|
2822
|
+
this.trackColorMaps.set(trackId, colorMap);
|
|
2823
|
+
}
|
|
2824
|
+
this.reapply();
|
|
2825
|
+
}
|
|
2826
|
+
registerClipAudio(reg) {
|
|
2827
|
+
this.ensureOrchestrator().registerClip(reg);
|
|
2828
|
+
}
|
|
2829
|
+
unregisterClipAudio(clipId) {
|
|
2830
|
+
this.orchestrator?.unregisterClip(clipId);
|
|
2831
|
+
}
|
|
2832
|
+
registerCanvas(reg) {
|
|
2833
|
+
this.ensureOrchestrator().registerCanvas(reg);
|
|
2834
|
+
}
|
|
2835
|
+
unregisterCanvas(canvasId) {
|
|
2836
|
+
this.orchestrator?.unregisterCanvas(canvasId);
|
|
2837
|
+
}
|
|
2838
|
+
setViewport(state5) {
|
|
2839
|
+
this.orchestrator?.setViewport(state5);
|
|
2840
|
+
}
|
|
2841
|
+
dispose() {
|
|
2842
|
+
if (this.orchestrator) {
|
|
2843
|
+
this.orchestrator.dispose();
|
|
2844
|
+
this.orchestrator = null;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
ensureOrchestrator() {
|
|
2848
|
+
if (!this.orchestrator) {
|
|
2849
|
+
this.orchestrator = new import_spectrogram.SpectrogramOrchestrator({
|
|
2850
|
+
workerFactory: this.workerFactory,
|
|
2851
|
+
workerPoolSize: 2,
|
|
2852
|
+
config: this.mergedConfig(),
|
|
2853
|
+
colorMap: this.mergedColorMap()
|
|
2854
|
+
});
|
|
2855
|
+
this.orchestrator.addEventListener("viewport-ready", (e) => {
|
|
2856
|
+
const detail = e.detail;
|
|
2857
|
+
this.host.dispatchEvent(
|
|
2858
|
+
new CustomEvent("daw-spectrogram-ready", {
|
|
2859
|
+
detail,
|
|
2860
|
+
bubbles: true,
|
|
2861
|
+
composed: true
|
|
2862
|
+
})
|
|
2863
|
+
);
|
|
2864
|
+
});
|
|
2865
|
+
this.reapply();
|
|
2866
|
+
}
|
|
2867
|
+
return this.orchestrator;
|
|
2868
|
+
}
|
|
2869
|
+
reapply() {
|
|
2870
|
+
if (!this.orchestrator) return;
|
|
2871
|
+
this.orchestrator.setConfig(this.mergedConfig());
|
|
2872
|
+
this.orchestrator.setColorMap(this.mergedColorMap());
|
|
2873
|
+
}
|
|
2874
|
+
mergedConfig() {
|
|
2875
|
+
let track = null;
|
|
2876
|
+
for (const c of this.trackConfigs.values()) {
|
|
2877
|
+
track = c;
|
|
2878
|
+
break;
|
|
2879
|
+
}
|
|
2880
|
+
return { ...LIBRARY_DEFAULTS, ...this.editorConfig ?? {}, ...track ?? {} };
|
|
2881
|
+
}
|
|
2882
|
+
mergedColorMap() {
|
|
2883
|
+
for (const c of this.trackColorMaps.values()) {
|
|
2884
|
+
return c ?? LIBRARY_DEFAULT_COLOR_MAP;
|
|
2885
|
+
}
|
|
2886
|
+
return this.editorColorMap ?? LIBRARY_DEFAULT_COLOR_MAP;
|
|
2887
|
+
}
|
|
2888
|
+
};
|
|
2889
|
+
|
|
2760
2890
|
// src/interactions/pointer-handler.ts
|
|
2761
2891
|
var import_core4 = require("@waveform-playlist/core");
|
|
2762
2892
|
|
|
@@ -3637,6 +3767,7 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
3637
3767
|
}
|
|
3638
3768
|
|
|
3639
3769
|
// src/elements/daw-editor.ts
|
|
3770
|
+
var import_meta = {};
|
|
3640
3771
|
var NO_ADAPTER_ERROR = "No PlayoutAdapter set on <daw-editor>. Set editor.adapter before use.\n\n // Option 1: Native Web Audio (no Tone.js)\n npm install @dawcore/transport\n import { NativePlayoutAdapter } from '@dawcore/transport';\n editor.adapter = new NativePlayoutAdapter(new AudioContext());\n\n // Option 2: Tone.js (effects, MIDI synths)\n npm install @waveform-playlist/playout\n import { createToneAdapter } from '@waveform-playlist/playout';\n editor.adapter = createToneAdapter();";
|
|
3641
3772
|
var DawEditorElement = class extends import_lit14.LitElement {
|
|
3642
3773
|
constructor() {
|
|
@@ -3652,6 +3783,8 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
3652
3783
|
this.clipHeaderHeight = 20;
|
|
3653
3784
|
this.interactiveClips = false;
|
|
3654
3785
|
this.indefinitePlayback = false;
|
|
3786
|
+
this._spectrogramConfig = null;
|
|
3787
|
+
this._spectrogramColorMap = null;
|
|
3655
3788
|
this.scaleMode = "temporal";
|
|
3656
3789
|
this._ticksPerPixel = 24;
|
|
3657
3790
|
this._bpm = 120;
|
|
@@ -3687,6 +3820,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
3687
3820
|
this._childObserver = null;
|
|
3688
3821
|
this._audioResume = new AudioResumeController(this);
|
|
3689
3822
|
this._recordingController = new RecordingController(this);
|
|
3823
|
+
this._spectrogramController = null;
|
|
3690
3824
|
this._clipPointer = new ClipPointerHandler(this);
|
|
3691
3825
|
this._pointer = new PointerHandler(this);
|
|
3692
3826
|
this._viewport = (() => {
|
|
@@ -3727,6 +3861,26 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
3727
3861
|
if (oldDescriptor?.src !== descriptor.src) {
|
|
3728
3862
|
this._loadTrack(trackId, descriptor);
|
|
3729
3863
|
}
|
|
3864
|
+
if (descriptor.renderMode === "spectrogram" && oldDescriptor?.renderMode !== "spectrogram") {
|
|
3865
|
+
const engineTrack = this._engineTracks.get(trackId);
|
|
3866
|
+
if (engineTrack) {
|
|
3867
|
+
for (const clip of engineTrack.clips) {
|
|
3868
|
+
this._maybeRegisterSpectrogramClipAudio(trackId, clip);
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
if (descriptor.renderMode !== "spectrogram" && oldDescriptor?.renderMode === "spectrogram") {
|
|
3873
|
+
const engineTrack = this._engineTracks.get(trackId);
|
|
3874
|
+
if (engineTrack && this._spectrogramController) {
|
|
3875
|
+
for (const clip of engineTrack.clips) {
|
|
3876
|
+
this._spectrogramController.unregisterClipAudio(clip.id);
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
this._disposeSpectrogramControllerIfEmpty();
|
|
3880
|
+
}
|
|
3881
|
+
if (descriptor.spectrogramConfig !== oldDescriptor?.spectrogramConfig) {
|
|
3882
|
+
this._spectrogramController?.setTrackConfig(trackId, descriptor.spectrogramConfig ?? null);
|
|
3883
|
+
}
|
|
3730
3884
|
};
|
|
3731
3885
|
this._onTrackControl = (e) => {
|
|
3732
3886
|
const { trackId, prop, value } = e.detail ?? {};
|
|
@@ -3870,6 +4024,72 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
3870
4024
|
this._samplesPerPixel = clamped;
|
|
3871
4025
|
this.requestUpdate("samplesPerPixel", old);
|
|
3872
4026
|
}
|
|
4027
|
+
get spectrogramConfig() {
|
|
4028
|
+
return this._spectrogramConfig;
|
|
4029
|
+
}
|
|
4030
|
+
set spectrogramConfig(value) {
|
|
4031
|
+
const old = this._spectrogramConfig;
|
|
4032
|
+
this._spectrogramConfig = value;
|
|
4033
|
+
this._spectrogramController?.setEditorConfig(value);
|
|
4034
|
+
this.requestUpdate("spectrogramConfig", old);
|
|
4035
|
+
}
|
|
4036
|
+
get spectrogramColorMap() {
|
|
4037
|
+
return this._spectrogramColorMap;
|
|
4038
|
+
}
|
|
4039
|
+
set spectrogramColorMap(value) {
|
|
4040
|
+
const old = this._spectrogramColorMap;
|
|
4041
|
+
this._spectrogramColorMap = value;
|
|
4042
|
+
this._spectrogramController?.setEditorColorMap(value);
|
|
4043
|
+
this.requestUpdate("spectrogramColorMap", old);
|
|
4044
|
+
}
|
|
4045
|
+
_ensureSpectrogramController() {
|
|
4046
|
+
if (!this._spectrogramController) {
|
|
4047
|
+
this._spectrogramController = new SpectrogramController(
|
|
4048
|
+
this,
|
|
4049
|
+
() => new Worker(new URL("@dawcore/spectrogram/worker/spectrogram.worker", import_meta.url), {
|
|
4050
|
+
type: "module"
|
|
4051
|
+
})
|
|
4052
|
+
);
|
|
4053
|
+
if (this._spectrogramConfig) {
|
|
4054
|
+
this._spectrogramController.setEditorConfig(this._spectrogramConfig);
|
|
4055
|
+
}
|
|
4056
|
+
if (this._spectrogramColorMap) {
|
|
4057
|
+
this._spectrogramController.setEditorColorMap(this._spectrogramColorMap);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
return this._spectrogramController;
|
|
4061
|
+
}
|
|
4062
|
+
/** Called by <daw-spectrogram> after transferControlToOffscreen. */
|
|
4063
|
+
_spectrogramRegisterCanvas(reg) {
|
|
4064
|
+
this._ensureSpectrogramController().registerCanvas(reg);
|
|
4065
|
+
}
|
|
4066
|
+
/** Called by <daw-spectrogram> on chunk unmount / element disconnect. */
|
|
4067
|
+
_spectrogramUnregisterCanvas(canvasId) {
|
|
4068
|
+
this._spectrogramController?.unregisterCanvas(canvasId);
|
|
4069
|
+
}
|
|
4070
|
+
/**
|
|
4071
|
+
* Push a clip's decoded audio into the spectrogram controller. No-op
|
|
4072
|
+
* unless the track is in spectrogram render-mode and the controller
|
|
4073
|
+
* already exists (it bootstraps from canvas registration).
|
|
4074
|
+
*/
|
|
4075
|
+
_maybeRegisterSpectrogramClipAudio(trackId, clip) {
|
|
4076
|
+
const descriptor = this._tracks.get(trackId);
|
|
4077
|
+
if (descriptor?.renderMode !== "spectrogram") return;
|
|
4078
|
+
const buffer = clip.audioBuffer ?? this._clipBuffers.get(clip.id);
|
|
4079
|
+
if (!buffer) return;
|
|
4080
|
+
const channelData = [];
|
|
4081
|
+
for (let i = 0; i < buffer.numberOfChannels; i++) {
|
|
4082
|
+
channelData.push(buffer.getChannelData(i));
|
|
4083
|
+
}
|
|
4084
|
+
this._ensureSpectrogramController().registerClipAudio({
|
|
4085
|
+
clipId: clip.id,
|
|
4086
|
+
trackId,
|
|
4087
|
+
channelData,
|
|
4088
|
+
sampleRate: buffer.sampleRate,
|
|
4089
|
+
durationSamples: clip.durationSamples,
|
|
4090
|
+
offsetSamples: clip.offsetSamples
|
|
4091
|
+
});
|
|
4092
|
+
}
|
|
3873
4093
|
get ticksPerPixel() {
|
|
3874
4094
|
return this._ticksPerPixel;
|
|
3875
4095
|
}
|
|
@@ -4110,6 +4330,8 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4110
4330
|
this._clipOffsets.clear();
|
|
4111
4331
|
this._peakPipeline.terminate();
|
|
4112
4332
|
this._minSamplesPerPixel = 0;
|
|
4333
|
+
this._spectrogramController?.dispose();
|
|
4334
|
+
this._spectrogramController = null;
|
|
4113
4335
|
try {
|
|
4114
4336
|
this._disposeEngine();
|
|
4115
4337
|
} catch (err) {
|
|
@@ -4138,6 +4360,23 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4138
4360
|
}
|
|
4139
4361
|
}
|
|
4140
4362
|
}
|
|
4363
|
+
updated(_changed) {
|
|
4364
|
+
if (this._spectrogramController) {
|
|
4365
|
+
const vs = this._viewport.visibleStart;
|
|
4366
|
+
const ve = this._viewport.visibleEnd;
|
|
4367
|
+
if (Number.isFinite(vs) && Number.isFinite(ve)) {
|
|
4368
|
+
const span = ve - vs;
|
|
4369
|
+
const bufferPad = span * 0.25;
|
|
4370
|
+
this._spectrogramController.setViewport({
|
|
4371
|
+
visibleStartPx: vs,
|
|
4372
|
+
visibleEndPx: ve,
|
|
4373
|
+
bufferStartPx: Math.max(0, vs - bufferPad),
|
|
4374
|
+
bufferEndPx: ve + bufferPad,
|
|
4375
|
+
samplesPerPixel: this._renderSpp
|
|
4376
|
+
});
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4141
4380
|
_onTrackRemoved(trackId) {
|
|
4142
4381
|
this._trackElements.delete(trackId);
|
|
4143
4382
|
const removedTrack = this._engineTracks.get(trackId);
|
|
@@ -4147,6 +4386,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4147
4386
|
this._clipBuffers.delete(clip.id);
|
|
4148
4387
|
this._clipOffsets.delete(clip.id);
|
|
4149
4388
|
nextPeaks.delete(clip.id);
|
|
4389
|
+
this._spectrogramController?.unregisterClipAudio(clip.id);
|
|
4150
4390
|
}
|
|
4151
4391
|
this._peaksData = nextPeaks;
|
|
4152
4392
|
}
|
|
@@ -4161,11 +4401,23 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4161
4401
|
this._engine.removeTrack(trackId);
|
|
4162
4402
|
}
|
|
4163
4403
|
this._minSamplesPerPixel = this._peakPipeline.getMaxCachedScale(this._clipBuffers);
|
|
4404
|
+
this._disposeSpectrogramControllerIfEmpty();
|
|
4164
4405
|
if (nextEngine.size === 0) {
|
|
4165
4406
|
this._currentTime = 0;
|
|
4166
4407
|
this._stopPlayhead();
|
|
4167
4408
|
}
|
|
4168
4409
|
}
|
|
4410
|
+
/** Drop the controller when no spectrogram tracks remain. */
|
|
4411
|
+
_disposeSpectrogramControllerIfEmpty() {
|
|
4412
|
+
if (!this._spectrogramController) return;
|
|
4413
|
+
const stillNeeded = Array.from(this._tracks.values()).some(
|
|
4414
|
+
(d) => d.renderMode === "spectrogram"
|
|
4415
|
+
);
|
|
4416
|
+
if (!stillNeeded) {
|
|
4417
|
+
this._spectrogramController.dispose();
|
|
4418
|
+
this._spectrogramController = null;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4169
4421
|
_onClipRemovedFromDom(clipEl) {
|
|
4170
4422
|
const clipId = clipEl.clipId;
|
|
4171
4423
|
for (const [trackId, t] of this._engineTracks.entries()) {
|
|
@@ -4207,6 +4459,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4207
4459
|
});
|
|
4208
4460
|
}
|
|
4209
4461
|
this._commitTrackChange(trackId, updatedTrack);
|
|
4462
|
+
this._maybeRegisterSpectrogramClipAudio(trackId, clip);
|
|
4210
4463
|
this.dispatchEvent(
|
|
4211
4464
|
new CustomEvent("daw-clip-ready", {
|
|
4212
4465
|
bubbles: true,
|
|
@@ -4381,6 +4634,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4381
4634
|
nextPeaks.delete(clipId);
|
|
4382
4635
|
this._peaksData = nextPeaks;
|
|
4383
4636
|
this._clipOffsets.delete(clipId);
|
|
4637
|
+
this._spectrogramController?.unregisterClipAudio(clipId);
|
|
4384
4638
|
}
|
|
4385
4639
|
/**
|
|
4386
4640
|
* Recompute duration and forward an updated track to the engine. Single
|
|
@@ -4663,6 +4917,9 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
4663
4917
|
track.id = trackId;
|
|
4664
4918
|
this._engineTracks = new Map(this._engineTracks).set(trackId, track);
|
|
4665
4919
|
this._recomputeDuration();
|
|
4920
|
+
for (const c of clips) {
|
|
4921
|
+
this._maybeRegisterSpectrogramClipAudio(trackId, c);
|
|
4922
|
+
}
|
|
4666
4923
|
const engine = await this._ensureEngine();
|
|
4667
4924
|
engine.setTracks([...this._engineTracks.values()]);
|
|
4668
4925
|
this.dispatchEvent(
|
|
@@ -5474,19 +5731,34 @@ var DawEditorElement = class extends import_lit14.LitElement {
|
|
|
5474
5731
|
.visibleEnd=${this._viewport.visibleEnd}
|
|
5475
5732
|
.originX=${clipLeft}
|
|
5476
5733
|
?selected=${t.trackId === this._selectedTrackId}
|
|
5477
|
-
></daw-piano-roll>` : channels.map(
|
|
5734
|
+
></daw-piano-roll>` : t.descriptor?.renderMode === "spectrogram" ? channels.map(
|
|
5735
|
+
(_chPeaks, chIdx) => import_lit14.html`<daw-spectrogram
|
|
5736
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;height:${chH}px;width:${peakData?.length ?? width}px;"
|
|
5737
|
+
.clipId=${clip.id}
|
|
5738
|
+
.trackId=${t.trackId}
|
|
5739
|
+
.channelIndex=${chIdx}
|
|
5740
|
+
.length=${peakData?.length ?? width}
|
|
5741
|
+
.waveHeight=${chH}
|
|
5742
|
+
.samplesPerPixel=${this._renderSpp}
|
|
5743
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
5744
|
+
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
5745
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
5746
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
5747
|
+
.originX=${clipLeft}
|
|
5748
|
+
></daw-spectrogram>`
|
|
5749
|
+
) : channels.map(
|
|
5478
5750
|
(chPeaks, chIdx) => import_lit14.html` <daw-waveform
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5751
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
5752
|
+
.peaks=${chPeaks}
|
|
5753
|
+
.length=${peakData?.length ?? width}
|
|
5754
|
+
.waveHeight=${chH}
|
|
5755
|
+
.barWidth=${this.barWidth}
|
|
5756
|
+
.barGap=${this.barGap}
|
|
5757
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
5758
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
5759
|
+
.originX=${clipLeft}
|
|
5760
|
+
.segments=${clipSegments}
|
|
5761
|
+
></daw-waveform>`
|
|
5490
5762
|
)}
|
|
5491
5763
|
${this.interactiveClips ? import_lit14.html` <div
|
|
5492
5764
|
class="clip-boundary"
|
|
@@ -5594,6 +5866,12 @@ __decorateClass([
|
|
|
5594
5866
|
__decorateClass([
|
|
5595
5867
|
(0, import_decorators12.property)({ type: Boolean, attribute: "indefinite-playback" })
|
|
5596
5868
|
], DawEditorElement.prototype, "indefinitePlayback", 2);
|
|
5869
|
+
__decorateClass([
|
|
5870
|
+
(0, import_decorators12.property)({ attribute: false, noAccessor: true })
|
|
5871
|
+
], DawEditorElement.prototype, "spectrogramConfig", 1);
|
|
5872
|
+
__decorateClass([
|
|
5873
|
+
(0, import_decorators12.property)({ attribute: false, noAccessor: true })
|
|
5874
|
+
], DawEditorElement.prototype, "spectrogramColorMap", 1);
|
|
5597
5875
|
__decorateClass([
|
|
5598
5876
|
(0, import_decorators12.property)({ type: String, attribute: "scale-mode" })
|
|
5599
5877
|
], DawEditorElement.prototype, "scaleMode", 2);
|
|
@@ -6172,6 +6450,187 @@ __decorateClass([
|
|
|
6172
6450
|
DawKeyboardShortcutsElement = __decorateClass([
|
|
6173
6451
|
(0, import_decorators16.customElement)("daw-keyboard-shortcuts")
|
|
6174
6452
|
], DawKeyboardShortcutsElement);
|
|
6453
|
+
|
|
6454
|
+
// src/elements/daw-spectrogram.ts
|
|
6455
|
+
var import_lit19 = require("lit");
|
|
6456
|
+
var import_decorators17 = require("lit/decorators.js");
|
|
6457
|
+
var MAX_CANVAS_WIDTH5 = 1e3;
|
|
6458
|
+
var DawSpectrogramElement = class extends import_lit19.LitElement {
|
|
6459
|
+
constructor() {
|
|
6460
|
+
super(...arguments);
|
|
6461
|
+
this.clipId = "";
|
|
6462
|
+
this.trackId = "";
|
|
6463
|
+
this.channelIndex = 0;
|
|
6464
|
+
this.length = 0;
|
|
6465
|
+
this.waveHeight = 128;
|
|
6466
|
+
this._samplesPerPixel = 1024;
|
|
6467
|
+
this._sampleRate = 44100;
|
|
6468
|
+
this.clipOffsetSeconds = 0;
|
|
6469
|
+
this.visibleStart = -Infinity;
|
|
6470
|
+
this.visibleEnd = Infinity;
|
|
6471
|
+
this.originX = 0;
|
|
6472
|
+
this._canvases = [];
|
|
6473
|
+
this._registeredCanvasIds = [];
|
|
6474
|
+
}
|
|
6475
|
+
get samplesPerPixel() {
|
|
6476
|
+
return this._samplesPerPixel;
|
|
6477
|
+
}
|
|
6478
|
+
set samplesPerPixel(value) {
|
|
6479
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
6480
|
+
console.warn("[dawcore] daw-spectrogram samplesPerPixel " + value + " is invalid \u2014 ignored");
|
|
6481
|
+
return;
|
|
6482
|
+
}
|
|
6483
|
+
const old = this._samplesPerPixel;
|
|
6484
|
+
this._samplesPerPixel = value;
|
|
6485
|
+
this.requestUpdate("samplesPerPixel", old);
|
|
6486
|
+
}
|
|
6487
|
+
get sampleRate() {
|
|
6488
|
+
return this._sampleRate;
|
|
6489
|
+
}
|
|
6490
|
+
set sampleRate(value) {
|
|
6491
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
6492
|
+
console.warn("[dawcore] daw-spectrogram sampleRate " + value + " is invalid \u2014 ignored");
|
|
6493
|
+
return;
|
|
6494
|
+
}
|
|
6495
|
+
const old = this._sampleRate;
|
|
6496
|
+
this._sampleRate = value;
|
|
6497
|
+
this.requestUpdate("sampleRate", old);
|
|
6498
|
+
}
|
|
6499
|
+
/**
|
|
6500
|
+
* Walk up to the editor host. `closest('daw-editor')` does NOT cross
|
|
6501
|
+
* shadow boundaries — and this element lives inside the editor's shadow
|
|
6502
|
+
* DOM — so use getRootNode().host to step out.
|
|
6503
|
+
*/
|
|
6504
|
+
_findHostEditor() {
|
|
6505
|
+
const root = this.getRootNode();
|
|
6506
|
+
const host = root instanceof ShadowRoot ? root.host : null;
|
|
6507
|
+
if (!host) return null;
|
|
6508
|
+
if (host.tagName === "DAW-EDITOR") return host;
|
|
6509
|
+
return host.closest("daw-editor");
|
|
6510
|
+
}
|
|
6511
|
+
willUpdate(changed) {
|
|
6512
|
+
const layoutChanged = changed.has("length") || changed.has("waveHeight") || changed.has("samplesPerPixel") || changed.has("clipId") || changed.has("channelIndex");
|
|
6513
|
+
if (layoutChanged) {
|
|
6514
|
+
this._rebuildChunks();
|
|
6515
|
+
}
|
|
6516
|
+
}
|
|
6517
|
+
_rebuildChunks() {
|
|
6518
|
+
this._unregisterAllCanvases();
|
|
6519
|
+
this._canvases = [];
|
|
6520
|
+
if (this.length <= 0) return;
|
|
6521
|
+
const chunkCount = Math.ceil(this.length / MAX_CANVAS_WIDTH5);
|
|
6522
|
+
for (let i = 0; i < chunkCount; i++) {
|
|
6523
|
+
const widthPx = Math.min(MAX_CANVAS_WIDTH5, this.length - i * MAX_CANVAS_WIDTH5);
|
|
6524
|
+
const canvas = document.createElement("canvas");
|
|
6525
|
+
canvas.style.left = i * MAX_CANVAS_WIDTH5 + "px";
|
|
6526
|
+
canvas.style.width = widthPx + "px";
|
|
6527
|
+
const dpr = window.devicePixelRatio || 1;
|
|
6528
|
+
canvas.width = widthPx * dpr;
|
|
6529
|
+
canvas.height = this.waveHeight * dpr;
|
|
6530
|
+
this._canvases.push(canvas);
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
updated(_changed) {
|
|
6534
|
+
if (this._registeredCanvasIds.length === 0 && this._canvases.length > 0) {
|
|
6535
|
+
requestAnimationFrame(() => this._registerCanvases());
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6538
|
+
_registerCanvases() {
|
|
6539
|
+
const editor = this._findHostEditor();
|
|
6540
|
+
if (!editor || typeof editor._spectrogramRegisterCanvas !== "function") return;
|
|
6541
|
+
for (let i = 0; i < this._canvases.length; i++) {
|
|
6542
|
+
const canvas = this._canvases[i];
|
|
6543
|
+
const canvasId = this.clipId + "-ch" + this.channelIndex + "-chunk" + i;
|
|
6544
|
+
let offscreen;
|
|
6545
|
+
try {
|
|
6546
|
+
offscreen = canvas.transferControlToOffscreen();
|
|
6547
|
+
} catch (err) {
|
|
6548
|
+
console.warn(
|
|
6549
|
+
"[dawcore] daw-spectrogram transferControlToOffscreen failed for " + canvasId + ": " + (err instanceof Error ? err.message : String(err))
|
|
6550
|
+
);
|
|
6551
|
+
continue;
|
|
6552
|
+
}
|
|
6553
|
+
editor._spectrogramRegisterCanvas({
|
|
6554
|
+
canvasId,
|
|
6555
|
+
canvas: offscreen,
|
|
6556
|
+
clipId: this.clipId,
|
|
6557
|
+
trackId: this.trackId,
|
|
6558
|
+
channelIndex: this.channelIndex,
|
|
6559
|
+
chunkIndex: i,
|
|
6560
|
+
globalPixelOffset: this.originX + i * MAX_CANVAS_WIDTH5,
|
|
6561
|
+
widthPx: parseFloat(canvas.style.width),
|
|
6562
|
+
heightPx: this.waveHeight
|
|
6563
|
+
});
|
|
6564
|
+
this._registeredCanvasIds.push(canvasId);
|
|
6565
|
+
}
|
|
6566
|
+
}
|
|
6567
|
+
_unregisterAllCanvases() {
|
|
6568
|
+
const editor = this._findHostEditor();
|
|
6569
|
+
if (editor && typeof editor._spectrogramUnregisterCanvas === "function") {
|
|
6570
|
+
for (const id of this._registeredCanvasIds) {
|
|
6571
|
+
editor._spectrogramUnregisterCanvas(id);
|
|
6572
|
+
}
|
|
6573
|
+
}
|
|
6574
|
+
this._registeredCanvasIds = [];
|
|
6575
|
+
}
|
|
6576
|
+
disconnectedCallback() {
|
|
6577
|
+
super.disconnectedCallback();
|
|
6578
|
+
this._unregisterAllCanvases();
|
|
6579
|
+
}
|
|
6580
|
+
render() {
|
|
6581
|
+
return import_lit19.html`${this._canvases.map((c) => c)}`;
|
|
6582
|
+
}
|
|
6583
|
+
};
|
|
6584
|
+
DawSpectrogramElement.styles = import_lit19.css`
|
|
6585
|
+
:host {
|
|
6586
|
+
display: block;
|
|
6587
|
+
position: relative;
|
|
6588
|
+
background: var(--daw-spectrogram-background, #000);
|
|
6589
|
+
}
|
|
6590
|
+
canvas {
|
|
6591
|
+
position: absolute;
|
|
6592
|
+
top: 0;
|
|
6593
|
+
left: 0;
|
|
6594
|
+
height: 100%;
|
|
6595
|
+
pointer-events: none;
|
|
6596
|
+
}
|
|
6597
|
+
`;
|
|
6598
|
+
__decorateClass([
|
|
6599
|
+
(0, import_decorators17.property)({ attribute: false })
|
|
6600
|
+
], DawSpectrogramElement.prototype, "clipId", 2);
|
|
6601
|
+
__decorateClass([
|
|
6602
|
+
(0, import_decorators17.property)({ attribute: false })
|
|
6603
|
+
], DawSpectrogramElement.prototype, "trackId", 2);
|
|
6604
|
+
__decorateClass([
|
|
6605
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6606
|
+
], DawSpectrogramElement.prototype, "channelIndex", 2);
|
|
6607
|
+
__decorateClass([
|
|
6608
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6609
|
+
], DawSpectrogramElement.prototype, "length", 2);
|
|
6610
|
+
__decorateClass([
|
|
6611
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6612
|
+
], DawSpectrogramElement.prototype, "waveHeight", 2);
|
|
6613
|
+
__decorateClass([
|
|
6614
|
+
(0, import_decorators17.property)({ type: Number, attribute: false, noAccessor: true })
|
|
6615
|
+
], DawSpectrogramElement.prototype, "samplesPerPixel", 1);
|
|
6616
|
+
__decorateClass([
|
|
6617
|
+
(0, import_decorators17.property)({ type: Number, attribute: false, noAccessor: true })
|
|
6618
|
+
], DawSpectrogramElement.prototype, "sampleRate", 1);
|
|
6619
|
+
__decorateClass([
|
|
6620
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6621
|
+
], DawSpectrogramElement.prototype, "clipOffsetSeconds", 2);
|
|
6622
|
+
__decorateClass([
|
|
6623
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6624
|
+
], DawSpectrogramElement.prototype, "visibleStart", 2);
|
|
6625
|
+
__decorateClass([
|
|
6626
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6627
|
+
], DawSpectrogramElement.prototype, "visibleEnd", 2);
|
|
6628
|
+
__decorateClass([
|
|
6629
|
+
(0, import_decorators17.property)({ type: Number, attribute: false })
|
|
6630
|
+
], DawSpectrogramElement.prototype, "originX", 2);
|
|
6631
|
+
DawSpectrogramElement = __decorateClass([
|
|
6632
|
+
(0, import_decorators17.customElement)("daw-spectrogram")
|
|
6633
|
+
], DawSpectrogramElement);
|
|
6175
6634
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6176
6635
|
0 && (module.exports = {
|
|
6177
6636
|
AudioResumeController,
|
|
@@ -6187,6 +6646,7 @@ DawKeyboardShortcutsElement = __decorateClass([
|
|
|
6187
6646
|
DawRecordButtonElement,
|
|
6188
6647
|
DawRulerElement,
|
|
6189
6648
|
DawSelectionElement,
|
|
6649
|
+
DawSpectrogramElement,
|
|
6190
6650
|
DawStopButtonElement,
|
|
6191
6651
|
DawTrackControlsElement,
|
|
6192
6652
|
DawTrackElement,
|
|
@@ -6194,6 +6654,7 @@ DawKeyboardShortcutsElement = __decorateClass([
|
|
|
6194
6654
|
DawTransportElement,
|
|
6195
6655
|
DawWaveformElement,
|
|
6196
6656
|
RecordingController,
|
|
6657
|
+
SpectrogramController,
|
|
6197
6658
|
isDomClip,
|
|
6198
6659
|
splitAtPlayhead
|
|
6199
6660
|
});
|