@dawcore/components 0.0.19 → 0.0.20

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.js CHANGED
@@ -230,7 +230,7 @@ var DawTrackElement = class extends import_lit2.LitElement {
230
230
  this.pan = 0;
231
231
  this.muted = false;
232
232
  this.soloed = false;
233
- this.renderMode = "waveform";
233
+ this._renderMode = "waveform";
234
234
  this.spectrogramConfig = null;
235
235
  this.trackId = crypto.randomUUID();
236
236
  // Track removal is detected by the editor's MutationObserver,
@@ -238,6 +238,21 @@ var DawTrackElement = class extends import_lit2.LitElement {
238
238
  // cannot bubble events to ancestors).
239
239
  this._hasRendered = false;
240
240
  }
241
+ get renderMode() {
242
+ return this._renderMode;
243
+ }
244
+ set renderMode(value) {
245
+ const old = this._renderMode;
246
+ let next = value;
247
+ if (next === "both") {
248
+ console.warn(
249
+ `[dawcore] <daw-track render-mode="both"> is not yet supported; falling back to 'spectrogram'`
250
+ );
251
+ next = "spectrogram";
252
+ }
253
+ this._renderMode = next;
254
+ this.requestUpdate("renderMode", old);
255
+ }
241
256
  // Light DOM so <daw-clip> children are queryable.
242
257
  createRenderRoot() {
243
258
  return this;
@@ -300,8 +315,8 @@ __decorateClass([
300
315
  (0, import_decorators2.property)({ type: Boolean })
301
316
  ], DawTrackElement.prototype, "soloed", 2);
302
317
  __decorateClass([
303
- (0, import_decorators2.property)({ attribute: "render-mode" })
304
- ], DawTrackElement.prototype, "renderMode", 2);
318
+ (0, import_decorators2.property)({ attribute: "render-mode", noAccessor: true })
319
+ ], DawTrackElement.prototype, "renderMode", 1);
305
320
  __decorateClass([
306
321
  (0, import_decorators2.property)({ attribute: false })
307
322
  ], DawTrackElement.prototype, "spectrogramConfig", 2);
@@ -1246,7 +1261,7 @@ function isDomClip(desc) {
1246
1261
  }
1247
1262
 
1248
1263
  // src/elements/daw-editor.ts
1249
- var import_core8 = require("@waveform-playlist/core");
1264
+ var import_core9 = require("@waveform-playlist/core");
1250
1265
 
1251
1266
  // src/workers/peaksWorker.ts
1252
1267
  var import_waveform_data = __toESM(require("waveform-data"));
@@ -2774,15 +2789,7 @@ var RecordingController = class {
2774
2789
 
2775
2790
  // src/controllers/spectrogram-controller.ts
2776
2791
  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";
2792
+ var import_core4 = require("@waveform-playlist/core");
2786
2793
  var SpectrogramController = class {
2787
2794
  constructor(host, workerFactory) {
2788
2795
  this.orchestrator = null;
@@ -2856,7 +2863,21 @@ var SpectrogramController = class {
2856
2863
  const detail = e.detail;
2857
2864
  this.host.dispatchEvent(
2858
2865
  new CustomEvent("daw-spectrogram-ready", {
2859
- detail,
2866
+ detail: { trackId: detail.trackId, generation: detail.generation },
2867
+ bubbles: true,
2868
+ composed: true
2869
+ })
2870
+ );
2871
+ });
2872
+ this.orchestrator.addEventListener("viewport-error", (e) => {
2873
+ const detail = e.detail;
2874
+ this.host.dispatchEvent(
2875
+ new CustomEvent("daw-spectrogram-error", {
2876
+ detail: {
2877
+ trackId: detail.trackId,
2878
+ generation: detail.generation,
2879
+ error: detail.error
2880
+ },
2860
2881
  bubbles: true,
2861
2882
  composed: true
2862
2883
  })
@@ -2877,18 +2898,18 @@ var SpectrogramController = class {
2877
2898
  track = c;
2878
2899
  break;
2879
2900
  }
2880
- return { ...LIBRARY_DEFAULTS, ...this.editorConfig ?? {}, ...track ?? {} };
2901
+ return { ...import_core4.SPECTROGRAM_DEFAULTS, ...this.editorConfig ?? {}, ...track ?? {} };
2881
2902
  }
2882
2903
  mergedColorMap() {
2883
2904
  for (const c of this.trackColorMaps.values()) {
2884
- return c ?? LIBRARY_DEFAULT_COLOR_MAP;
2905
+ return c ?? import_core4.DEFAULT_SPECTROGRAM_COLOR_MAP;
2885
2906
  }
2886
- return this.editorColorMap ?? LIBRARY_DEFAULT_COLOR_MAP;
2907
+ return this.editorColorMap ?? import_core4.DEFAULT_SPECTROGRAM_COLOR_MAP;
2887
2908
  }
2888
2909
  };
2889
2910
 
2890
2911
  // src/interactions/pointer-handler.ts
2891
- var import_core4 = require("@waveform-playlist/core");
2912
+ var import_core5 = require("@waveform-playlist/core");
2892
2913
 
2893
2914
  // src/interactions/constants.ts
2894
2915
  var DRAG_THRESHOLD = 3;
@@ -2998,10 +3019,10 @@ var PointerHandler = class {
2998
3019
  const h = this._host;
2999
3020
  if (h.scaleMode === "beats") {
3000
3021
  let tick = px * h.ticksPerPixel;
3001
- tick = (0, import_core4.snapTickToGrid)(tick, h.snapTo, h._meterEntries, h.ppqn);
3022
+ tick = (0, import_core5.snapTickToGrid)(tick, h.snapTo, h._meterEntries, h.ppqn);
3002
3023
  return h._ticksToSeconds(tick);
3003
3024
  }
3004
- return (0, import_core4.pixelsToSeconds)(px, h.samplesPerPixel, h.effectiveSampleRate);
3025
+ return (0, import_core5.pixelsToSeconds)(px, h.samplesPerPixel, h.effectiveSampleRate);
3005
3026
  }
3006
3027
  _timeToPx(time) {
3007
3028
  const h = this._host;
@@ -3093,7 +3114,7 @@ var PointerHandler = class {
3093
3114
  };
3094
3115
 
3095
3116
  // src/interactions/clip-pointer-handler.ts
3096
- var import_core5 = require("@waveform-playlist/core");
3117
+ var import_core6 = require("@waveform-playlist/core");
3097
3118
  var ClipPointerHandler = class {
3098
3119
  constructor(host) {
3099
3120
  this._mode = null;
@@ -3127,7 +3148,7 @@ var ClipPointerHandler = class {
3127
3148
  const anchorTick = h._secondsToTicks(anchorSeconds);
3128
3149
  const deltaTicks = totalDeltaPx * h.ticksPerPixel;
3129
3150
  const targetTick = anchorTick + deltaTicks;
3130
- const snappedTick = h.snapTo !== "off" ? (0, import_core5.snapTickToGrid)(targetTick, h.snapTo, h._meterEntries, h.ppqn) : targetTick;
3151
+ const snappedTick = h.snapTo !== "off" ? (0, import_core6.snapTickToGrid)(targetTick, h.snapTo, h._meterEntries, h.ppqn) : targetTick;
3131
3152
  const snappedSeconds = h._ticksToSeconds(snappedTick);
3132
3153
  const snappedSample = Math.round(snappedSeconds * h.effectiveSampleRate);
3133
3154
  return snappedSample - anchorSample;
@@ -3390,7 +3411,7 @@ var ClipPointerHandler = class {
3390
3411
  };
3391
3412
 
3392
3413
  // src/interactions/file-loader.ts
3393
- var import_core6 = require("@waveform-playlist/core");
3414
+ var import_core7 = require("@waveform-playlist/core");
3394
3415
  async function loadFiles(host, files) {
3395
3416
  if (!files) {
3396
3417
  console.warn("[dawcore] loadFiles called with null/undefined");
@@ -3412,7 +3433,7 @@ async function loadFiles(host, files) {
3412
3433
  host._audioCache.delete(blobUrl);
3413
3434
  host._resolvedSampleRate = audioBuffer.sampleRate;
3414
3435
  const name = file.name.replace(/\.\w+$/, "");
3415
- const clip = (0, import_core6.createClip)({
3436
+ const clip = (0, import_core7.createClip)({
3416
3437
  audioBuffer,
3417
3438
  startSample: 0,
3418
3439
  durationSamples: audioBuffer.length,
@@ -3436,7 +3457,7 @@ async function loadFiles(host, files) {
3436
3457
  );
3437
3458
  host._peaksData = new Map(host._peaksData).set(clip.id, peakData);
3438
3459
  const trackId = crypto.randomUUID();
3439
- const track = (0, import_core6.createTrack)({ name, clips: [clip] });
3460
+ const track = (0, import_core7.createTrack)({ name, clips: [clip] });
3440
3461
  track.id = trackId;
3441
3462
  host._tracks = new Map(host._tracks).set(trackId, {
3442
3463
  name,
@@ -3598,7 +3619,7 @@ function stringifyReason(reason) {
3598
3619
  }
3599
3620
 
3600
3621
  // src/interactions/recording-clip.ts
3601
- var import_core7 = require("@waveform-playlist/core");
3622
+ var import_core8 = require("@waveform-playlist/core");
3602
3623
  function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamples = 0) {
3603
3624
  let trimmedBuf = buf;
3604
3625
  if (offsetSamples > 0 && offsetSamples < buf.length) {
@@ -3613,7 +3634,7 @@ function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamp
3613
3634
  }
3614
3635
  trimmedBuf = trimmed;
3615
3636
  }
3616
- const clip = (0, import_core7.createClip)({
3637
+ const clip = (0, import_core8.createClip)({
3617
3638
  audioBuffer: trimmedBuf,
3618
3639
  startSample,
3619
3640
  durationSamples: durSamples,
@@ -3936,7 +3957,10 @@ var DawEditorElement = class extends import_lit14.LitElement {
3936
3957
  * `_selectedTrackId`, etc.) — most of which don't affect the spectrogram
3937
3958
  * viewport. Skip the cross-controller call when nothing changed.
3938
3959
  *
3939
- * The orchestrator dedupes too, but this avoids the call entirely.
3960
+ * The orchestrator dedupes identical viewports too, so removing this cache
3961
+ * wouldn't change observable behavior — but it would push a fresh
3962
+ * `setViewport` call (with object allocation) into every Lit reactive
3963
+ * update for properties unrelated to the viewport.
3940
3964
  */
3941
3965
  this._lastSpectrogramViewport = null;
3942
3966
  // --- Track Events ---
@@ -4179,9 +4203,10 @@ var DawEditorElement = class extends import_lit14.LitElement {
4179
4203
  this._spectrogramController?.unregisterCanvas(canvasId);
4180
4204
  }
4181
4205
  /**
4182
- * Push a clip's decoded audio into the spectrogram controller. No-op
4183
- * unless the track is in spectrogram render-mode and the controller
4184
- * already exists (it bootstraps from canvas registration).
4206
+ * Forward a clip's AudioBuffer to the spectrogram controller if the parent
4207
+ * track is in spectrogram render-mode. Eagerly creates the controller via
4208
+ * `_ensureSpectrogramController` so the audio data is queued for the first
4209
+ * render — even if no canvases have been registered yet.
4185
4210
  */
4186
4211
  _maybeRegisterSpectrogramClipAudio(trackId, clip) {
4187
4212
  const descriptor = this._tracks.get(trackId);
@@ -4632,7 +4657,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
4632
4657
  let clip;
4633
4658
  if (waveformData) {
4634
4659
  const wdRate = waveformData.sample_rate;
4635
- clip = (0, import_core8.createClip)({
4660
+ clip = (0, import_core9.createClip)({
4636
4661
  audioBuffer,
4637
4662
  waveformData,
4638
4663
  startSample: Math.round(clipDesc.start * wdRate),
@@ -4645,7 +4670,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
4645
4670
  });
4646
4671
  this._peakPipeline.cacheWaveformData(audioBuffer, waveformData);
4647
4672
  } else {
4648
- clip = (0, import_core8.createClipFromSeconds)({
4673
+ clip = (0, import_core9.createClipFromSeconds)({
4649
4674
  audioBuffer,
4650
4675
  startTime: clipDesc.start,
4651
4676
  duration: clipDesc.duration || audioBuffer.duration,
@@ -4725,7 +4750,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
4725
4750
  const noteSpanSeconds = notes.length ? notes.reduce((max, n) => Math.max(max, n.time + n.duration), 0) : 0;
4726
4751
  const sourceDurationSamples = Math.ceil(Math.max(noteSpanSeconds, clipDesc.duration, 1) * sr);
4727
4752
  const requestedDurationSamples = clipDesc.duration > 0 ? Math.round(clipDesc.duration * sr) : sourceDurationSamples;
4728
- const clip = (0, import_core8.createClip)({
4753
+ const clip = (0, import_core9.createClip)({
4729
4754
  startSample: Math.round(clipDesc.start * sr),
4730
4755
  durationSamples: requestedDurationSamples,
4731
4756
  offsetSamples: Math.round(clipDesc.offset * sr),
@@ -4934,7 +4959,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
4934
4959
  const waveformData = await waveformDataPromise;
4935
4960
  if (waveformData) {
4936
4961
  const wdRate = waveformData.sample_rate;
4937
- const clip2 = (0, import_core8.createClip)({
4962
+ const clip2 = (0, import_core9.createClip)({
4938
4963
  waveformData,
4939
4964
  startSample: Math.round(clipDesc.start * wdRate),
4940
4965
  durationSamples: Math.round((clipDesc.duration || waveformData.duration) * wdRate),
@@ -4959,7 +4984,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
4959
4984
  });
4960
4985
  this._peaksData = new Map(this._peaksData).set(clip2.id, peakData);
4961
4986
  this._minSamplesPerPixel = Math.max(this._minSamplesPerPixel, waveformData.scale);
4962
- const previewTrack = (0, import_core8.createTrack)({
4987
+ const previewTrack = (0, import_core9.createTrack)({
4963
4988
  name: descriptor.name,
4964
4989
  clips: [clip2],
4965
4990
  volume: descriptor.volume,
@@ -5015,7 +5040,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
5015
5040
  }
5016
5041
  }
5017
5042
  }
5018
- const track = (0, import_core8.createTrack)({
5043
+ const track = (0, import_core9.createTrack)({
5019
5044
  name: descriptor.name,
5020
5045
  clips,
5021
5046
  volume: descriptor.volume,
@@ -5298,6 +5323,13 @@ var DawEditorElement = class extends import_lit14.LitElement {
5298
5323
  }
5299
5324
  const oldDesc = this._tracks.get(trackId);
5300
5325
  if (!oldDesc) return;
5326
+ let normalizedRenderMode = partial.renderMode;
5327
+ if (normalizedRenderMode === "both") {
5328
+ console.warn(
5329
+ `[dawcore] render-mode="both" is not yet supported; falling back to 'spectrogram'`
5330
+ );
5331
+ normalizedRenderMode = "spectrogram";
5332
+ }
5301
5333
  const newDesc = {
5302
5334
  ...oldDesc,
5303
5335
  ...partial.name !== void 0 && { name: partial.name },
@@ -5305,7 +5337,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
5305
5337
  ...partial.pan !== void 0 && { pan: partial.pan },
5306
5338
  ...partial.muted !== void 0 && { muted: partial.muted },
5307
5339
  ...partial.soloed !== void 0 && { soloed: partial.soloed },
5308
- ...partial.renderMode !== void 0 && { renderMode: partial.renderMode }
5340
+ ...normalizedRenderMode !== void 0 && { renderMode: normalizedRenderMode }
5309
5341
  };
5310
5342
  this._tracks = new Map(this._tracks).set(trackId, newDesc);
5311
5343
  if (this._engine) {
@@ -5793,7 +5825,7 @@ var DawEditorElement = class extends import_lit14.LitElement {
5793
5825
  width = Math.round(endTick / this.ticksPerPixel) - clipLeft;
5794
5826
  } else {
5795
5827
  clipLeft = Math.floor(clip.startSample / spp);
5796
- width = (0, import_core8.clipPixelWidth)(clip.startSample, clip.durationSamples, spp);
5828
+ width = (0, import_core9.clipPixelWidth)(clip.startSample, clip.durationSamples, spp);
5797
5829
  }
5798
5830
  let clipSegments;
5799
5831
  let segmentChannels;
@@ -6415,7 +6447,7 @@ DawRecordButtonElement = __decorateClass([
6415
6447
  // src/elements/daw-keyboard-shortcuts.ts
6416
6448
  var import_lit18 = require("lit");
6417
6449
  var import_decorators16 = require("lit/decorators.js");
6418
- var import_core9 = require("@waveform-playlist/core");
6450
+ var import_core10 = require("@waveform-playlist/core");
6419
6451
  var DawKeyboardShortcutsElement = class extends import_lit18.LitElement {
6420
6452
  constructor() {
6421
6453
  super(...arguments);
@@ -6435,7 +6467,7 @@ var DawKeyboardShortcutsElement = class extends import_lit18.LitElement {
6435
6467
  const shortcuts = this.shortcuts;
6436
6468
  if (shortcuts.length === 0) return;
6437
6469
  try {
6438
- (0, import_core9.handleKeyboardEvent)(e, shortcuts, true);
6470
+ (0, import_core10.handleKeyboardEvent)(e, shortcuts, true);
6439
6471
  } catch (err) {
6440
6472
  console.warn("[dawcore] Keyboard shortcut failed (key=" + e.key + "): " + String(err));
6441
6473
  const target = this._editor ?? this;
@@ -6602,6 +6634,7 @@ var DawSpectrogramElement = class extends import_lit19.LitElement {
6602
6634
  this.originX = 0;
6603
6635
  this._canvases = [];
6604
6636
  this._registeredCanvasIds = [];
6637
+ this._warnedNoHost = false;
6605
6638
  }
6606
6639
  get samplesPerPixel() {
6607
6640
  return this._samplesPerPixel;
@@ -6668,7 +6701,15 @@ var DawSpectrogramElement = class extends import_lit19.LitElement {
6668
6701
  }
6669
6702
  _registerCanvases() {
6670
6703
  const editor = this._findHostEditor();
6671
- if (!editor || typeof editor._spectrogramRegisterCanvas !== "function") return;
6704
+ if (!editor || typeof editor._spectrogramRegisterCanvas !== "function") {
6705
+ if (!this._warnedNoHost) {
6706
+ this._warnedNoHost = true;
6707
+ console.warn(
6708
+ "[dawcore] <daw-spectrogram> (clip " + this.clipId + ") could not find host <daw-editor>. Canvases will not render. Ensure the element is mounted inside a <daw-editor>."
6709
+ );
6710
+ }
6711
+ return;
6712
+ }
6672
6713
  for (let i = 0; i < this._canvases.length; i++) {
6673
6714
  const canvas = this._canvases[i];
6674
6715
  const canvasId = this.clipId + "-ch" + this.channelIndex + "-chunk" + i;