@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.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as lit from 'lit';
2
2
  import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost } from 'lit';
3
- import { MidiNoteData, SpectrogramConfig, FadeType, Peaks, Bits, PeakData, MeterEntry, SnapTo, ColorMapValue, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
3
+ import { MidiNoteData, RenderMode, SpectrogramConfig, Peaks, Bits, FadeType, PeakData, MeterEntry, SnapTo, ColorMapValue, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
4
4
  import WaveformData from 'waveform-data';
5
5
  import { PlayoutAdapter, PlaylistEngine } from '@waveform-playlist/engine';
6
6
  import { MidiLoadOptions, MidiLoadResult } from '@dawcore/midi';
@@ -46,113 +46,6 @@ declare global {
46
46
  }
47
47
  }
48
48
 
49
- type TrackRenderMode = 'waveform' | 'piano-roll' | 'spectrogram';
50
- interface TrackDescriptor {
51
- name: string;
52
- src: string;
53
- volume: number;
54
- pan: number;
55
- muted: boolean;
56
- soloed: boolean;
57
- renderMode: TrackRenderMode;
58
- spectrogramConfig?: SpectrogramConfig | null;
59
- clips: ClipDescriptor[];
60
- }
61
- /**
62
- * Common fields shared by all clip descriptors regardless of source.
63
- */
64
- interface BaseClipDescriptor {
65
- src: string;
66
- peaksSrc: string;
67
- start: number;
68
- duration: number;
69
- offset: number;
70
- gain: number;
71
- name: string;
72
- fadeIn: number;
73
- fadeOut: number;
74
- fadeType: FadeType;
75
- midiNotes: MidiNoteData[] | null;
76
- midiChannel: number | null;
77
- midiProgram: number | null;
78
- }
79
- /**
80
- * A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
81
- * always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
82
- * construction. Engine `clip.id` is aligned with this id in `_loadTrack`
83
- * and `_loadAndAppendClip` so DOM and engine reference the same clip.
84
- */
85
- interface DomClipDescriptor extends BaseClipDescriptor {
86
- kind: 'dom';
87
- clipId: string;
88
- }
89
- /**
90
- * A clip descriptor synthesized from a non-DOM source — file drops, the
91
- * `<daw-track src>` shorthand fallback, or recording-clip insertion. No
92
- * `clipId` because there's no DOM element to align with; the engine
93
- * generates its own id at clip-creation time.
94
- */
95
- interface DropClipDescriptor extends BaseClipDescriptor {
96
- kind: 'drop';
97
- }
98
- type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
99
- /**
100
- * Type predicate for the `'dom'` discriminator. Use to narrow a
101
- * `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
102
- * inline `c.kind === 'dom'` repetition.
103
- */
104
- declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
105
- /**
106
- * Public input shape for `editor.addTrack(config)`. All fields optional —
107
- * defaults match the declarative `<daw-track>` defaults.
108
- */
109
- interface TrackConfig {
110
- name?: string;
111
- volume?: number;
112
- pan?: number;
113
- muted?: boolean;
114
- soloed?: boolean;
115
- renderMode?: TrackRenderMode;
116
- spectrogramConfig?: SpectrogramConfig | null;
117
- clips?: ClipConfig[];
118
- /**
119
- * Convenience: creates a single piano-roll `<daw-clip>` child with these
120
- * notes and sets `render-mode="piano-roll"` on the track. Equivalent to
121
- * passing `{ renderMode: 'piano-roll', clips: [{ midiNotes, midiChannel, midiProgram }] }`.
122
- * An explicit `renderMode` takes precedence over the inferred `'piano-roll'`.
123
- *
124
- * Creation-only — ignored by `updateTrack`. To modify notes after the
125
- * track is built, use `editor.updateClip(trackId, clipId, { midiNotes })` or
126
- * mutate the `<daw-clip>` element's `midiNotes` property directly.
127
- */
128
- midi?: {
129
- notes: MidiNoteData[];
130
- channel?: number;
131
- program?: number;
132
- };
133
- }
134
- /**
135
- * Public input shape for clips passed via `TrackConfig.clips` or
136
- * `editor.addClip(trackId, config)`. `src` is optional to support MIDI clips
137
- * with no audio source. Other fields default to the matching `<daw-clip>`
138
- * attribute defaults.
139
- */
140
- interface ClipConfig {
141
- src?: string;
142
- peaksSrc?: string;
143
- start?: number;
144
- duration?: number;
145
- offset?: number;
146
- gain?: number;
147
- name?: string;
148
- fadeIn?: number;
149
- fadeOut?: number;
150
- fadeType?: FadeType;
151
- midiNotes?: MidiNoteData[];
152
- midiChannel?: number;
153
- midiProgram?: number;
154
- }
155
-
156
49
  declare class DawTrackElement extends LitElement {
157
50
  src: string;
158
51
  name: string;
@@ -160,7 +53,9 @@ declare class DawTrackElement extends LitElement {
160
53
  pan: number;
161
54
  muted: boolean;
162
55
  soloed: boolean;
163
- renderMode: TrackRenderMode;
56
+ get renderMode(): RenderMode;
57
+ set renderMode(value: RenderMode);
58
+ private _renderMode;
164
59
  spectrogramConfig: SpectrogramConfig | null;
165
60
  readonly trackId: `${string}-${string}-${string}-${string}-${string}`;
166
61
  createRenderRoot(): this;
@@ -360,6 +255,113 @@ declare global {
360
255
  }
361
256
  }
362
257
 
258
+ type TrackRenderMode = RenderMode;
259
+ interface TrackDescriptor {
260
+ name: string;
261
+ src: string;
262
+ volume: number;
263
+ pan: number;
264
+ muted: boolean;
265
+ soloed: boolean;
266
+ renderMode: TrackRenderMode;
267
+ spectrogramConfig?: SpectrogramConfig | null;
268
+ clips: ClipDescriptor[];
269
+ }
270
+ /**
271
+ * Common fields shared by all clip descriptors regardless of source.
272
+ */
273
+ interface BaseClipDescriptor {
274
+ src: string;
275
+ peaksSrc: string;
276
+ start: number;
277
+ duration: number;
278
+ offset: number;
279
+ gain: number;
280
+ name: string;
281
+ fadeIn: number;
282
+ fadeOut: number;
283
+ fadeType: FadeType;
284
+ midiNotes: MidiNoteData[] | null;
285
+ midiChannel: number | null;
286
+ midiProgram: number | null;
287
+ }
288
+ /**
289
+ * A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
290
+ * always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
291
+ * construction. Engine `clip.id` is aligned with this id in `_loadTrack`
292
+ * and `_loadAndAppendClip` so DOM and engine reference the same clip.
293
+ */
294
+ interface DomClipDescriptor extends BaseClipDescriptor {
295
+ kind: 'dom';
296
+ clipId: string;
297
+ }
298
+ /**
299
+ * A clip descriptor synthesized from a non-DOM source — file drops, the
300
+ * `<daw-track src>` shorthand fallback, or recording-clip insertion. No
301
+ * `clipId` because there's no DOM element to align with; the engine
302
+ * generates its own id at clip-creation time.
303
+ */
304
+ interface DropClipDescriptor extends BaseClipDescriptor {
305
+ kind: 'drop';
306
+ }
307
+ type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
308
+ /**
309
+ * Type predicate for the `'dom'` discriminator. Use to narrow a
310
+ * `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
311
+ * inline `c.kind === 'dom'` repetition.
312
+ */
313
+ declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
314
+ /**
315
+ * Public input shape for `editor.addTrack(config)`. All fields optional —
316
+ * defaults match the declarative `<daw-track>` defaults.
317
+ */
318
+ interface TrackConfig {
319
+ name?: string;
320
+ volume?: number;
321
+ pan?: number;
322
+ muted?: boolean;
323
+ soloed?: boolean;
324
+ renderMode?: TrackRenderMode;
325
+ spectrogramConfig?: SpectrogramConfig | null;
326
+ clips?: ClipConfig[];
327
+ /**
328
+ * Convenience: creates a single piano-roll `<daw-clip>` child with these
329
+ * notes and sets `render-mode="piano-roll"` on the track. Equivalent to
330
+ * passing `{ renderMode: 'piano-roll', clips: [{ midiNotes, midiChannel, midiProgram }] }`.
331
+ * An explicit `renderMode` takes precedence over the inferred `'piano-roll'`.
332
+ *
333
+ * Creation-only — ignored by `updateTrack`. To modify notes after the
334
+ * track is built, use `editor.updateClip(trackId, clipId, { midiNotes })` or
335
+ * mutate the `<daw-clip>` element's `midiNotes` property directly.
336
+ */
337
+ midi?: {
338
+ notes: MidiNoteData[];
339
+ channel?: number;
340
+ program?: number;
341
+ };
342
+ }
343
+ /**
344
+ * Public input shape for clips passed via `TrackConfig.clips` or
345
+ * `editor.addClip(trackId, config)`. `src` is optional to support MIDI clips
346
+ * with no audio source. Other fields default to the matching `<daw-clip>`
347
+ * attribute defaults.
348
+ */
349
+ interface ClipConfig {
350
+ src?: string;
351
+ peaksSrc?: string;
352
+ start?: number;
353
+ duration?: number;
354
+ offset?: number;
355
+ gain?: number;
356
+ name?: string;
357
+ fadeIn?: number;
358
+ fadeOut?: number;
359
+ fadeType?: FadeType;
360
+ midiNotes?: MidiNoteData[];
361
+ midiChannel?: number;
362
+ midiProgram?: number;
363
+ }
364
+
363
365
  /**
364
366
  * Peak generation pipeline: AudioBuffer → web worker → WaveformData → PeakData.
365
367
  *
@@ -792,6 +794,12 @@ interface DawClipSplitDetail {
792
794
  }
793
795
  interface DawSpectrogramReadyDetail {
794
796
  trackId: string;
797
+ generation: number;
798
+ }
799
+ interface DawSpectrogramErrorDetail {
800
+ trackId: string;
801
+ generation: number;
802
+ error: Error;
795
803
  }
796
804
  interface DawEventMap {
797
805
  'daw-selection': CustomEvent<DawSelectionDetail>;
@@ -821,6 +829,7 @@ interface DawEventMap {
821
829
  'daw-clip-trim': CustomEvent<DawClipTrimDetail>;
822
830
  'daw-clip-split': CustomEvent<DawClipSplitDetail>;
823
831
  'daw-spectrogram-ready': CustomEvent<DawSpectrogramReadyDetail>;
832
+ 'daw-spectrogram-error': CustomEvent<DawSpectrogramErrorDetail>;
824
833
  }
825
834
  type DawEvent<K extends keyof DawEventMap> = DawEventMap[K];
826
835
  interface LoadFilesResult {
@@ -906,9 +915,10 @@ declare class DawEditorElement extends LitElement implements MidiLoaderHost {
906
915
  /** Called by <daw-spectrogram> on chunk unmount / element disconnect. */
907
916
  _spectrogramUnregisterCanvas(canvasId: string): void;
908
917
  /**
909
- * Push a clip's decoded audio into the spectrogram controller. No-op
910
- * unless the track is in spectrogram render-mode and the controller
911
- * already exists (it bootstraps from canvas registration).
918
+ * Forward a clip's AudioBuffer to the spectrogram controller if the parent
919
+ * track is in spectrogram render-mode. Eagerly creates the controller via
920
+ * `_ensureSpectrogramController` so the audio data is queued for the first
921
+ * render — even if no canvases have been registered yet.
912
922
  */
913
923
  private _maybeRegisterSpectrogramClipAudio;
914
924
  scaleMode: 'temporal' | 'beats';
@@ -1014,7 +1024,10 @@ declare class DawEditorElement extends LitElement implements MidiLoaderHost {
1014
1024
  * `_selectedTrackId`, etc.) — most of which don't affect the spectrogram
1015
1025
  * viewport. Skip the cross-controller call when nothing changed.
1016
1026
  *
1017
- * The orchestrator dedupes too, but this avoids the call entirely.
1027
+ * The orchestrator dedupes identical viewports too, so removing this cache
1028
+ * wouldn't change observable behavior — but it would push a fresh
1029
+ * `setViewport` call (with object allocation) into every Lit reactive
1030
+ * update for properties unrelated to the viewport.
1018
1031
  */
1019
1032
  private _lastSpectrogramViewport;
1020
1033
  protected updated(_changed: Map<string, unknown>): void;
@@ -1349,6 +1362,7 @@ declare class DawSpectrogramElement extends LitElement {
1349
1362
  static styles: lit.CSSResult;
1350
1363
  private _canvases;
1351
1364
  private _registeredCanvasIds;
1365
+ private _warnedNoHost;
1352
1366
  /**
1353
1367
  * Walk up to the editor host. `closest('daw-editor')` does NOT cross
1354
1368
  * shadow boundaries — and this element lives inside the editor's shadow
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as lit from 'lit';
2
2
  import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost } from 'lit';
3
- import { MidiNoteData, SpectrogramConfig, FadeType, Peaks, Bits, PeakData, MeterEntry, SnapTo, ColorMapValue, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
3
+ import { MidiNoteData, RenderMode, SpectrogramConfig, Peaks, Bits, FadeType, PeakData, MeterEntry, SnapTo, ColorMapValue, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
4
4
  import WaveformData from 'waveform-data';
5
5
  import { PlayoutAdapter, PlaylistEngine } from '@waveform-playlist/engine';
6
6
  import { MidiLoadOptions, MidiLoadResult } from '@dawcore/midi';
@@ -46,113 +46,6 @@ declare global {
46
46
  }
47
47
  }
48
48
 
49
- type TrackRenderMode = 'waveform' | 'piano-roll' | 'spectrogram';
50
- interface TrackDescriptor {
51
- name: string;
52
- src: string;
53
- volume: number;
54
- pan: number;
55
- muted: boolean;
56
- soloed: boolean;
57
- renderMode: TrackRenderMode;
58
- spectrogramConfig?: SpectrogramConfig | null;
59
- clips: ClipDescriptor[];
60
- }
61
- /**
62
- * Common fields shared by all clip descriptors regardless of source.
63
- */
64
- interface BaseClipDescriptor {
65
- src: string;
66
- peaksSrc: string;
67
- start: number;
68
- duration: number;
69
- offset: number;
70
- gain: number;
71
- name: string;
72
- fadeIn: number;
73
- fadeOut: number;
74
- fadeType: FadeType;
75
- midiNotes: MidiNoteData[] | null;
76
- midiChannel: number | null;
77
- midiProgram: number | null;
78
- }
79
- /**
80
- * A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
81
- * always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
82
- * construction. Engine `clip.id` is aligned with this id in `_loadTrack`
83
- * and `_loadAndAppendClip` so DOM and engine reference the same clip.
84
- */
85
- interface DomClipDescriptor extends BaseClipDescriptor {
86
- kind: 'dom';
87
- clipId: string;
88
- }
89
- /**
90
- * A clip descriptor synthesized from a non-DOM source — file drops, the
91
- * `<daw-track src>` shorthand fallback, or recording-clip insertion. No
92
- * `clipId` because there's no DOM element to align with; the engine
93
- * generates its own id at clip-creation time.
94
- */
95
- interface DropClipDescriptor extends BaseClipDescriptor {
96
- kind: 'drop';
97
- }
98
- type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
99
- /**
100
- * Type predicate for the `'dom'` discriminator. Use to narrow a
101
- * `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
102
- * inline `c.kind === 'dom'` repetition.
103
- */
104
- declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
105
- /**
106
- * Public input shape for `editor.addTrack(config)`. All fields optional —
107
- * defaults match the declarative `<daw-track>` defaults.
108
- */
109
- interface TrackConfig {
110
- name?: string;
111
- volume?: number;
112
- pan?: number;
113
- muted?: boolean;
114
- soloed?: boolean;
115
- renderMode?: TrackRenderMode;
116
- spectrogramConfig?: SpectrogramConfig | null;
117
- clips?: ClipConfig[];
118
- /**
119
- * Convenience: creates a single piano-roll `<daw-clip>` child with these
120
- * notes and sets `render-mode="piano-roll"` on the track. Equivalent to
121
- * passing `{ renderMode: 'piano-roll', clips: [{ midiNotes, midiChannel, midiProgram }] }`.
122
- * An explicit `renderMode` takes precedence over the inferred `'piano-roll'`.
123
- *
124
- * Creation-only — ignored by `updateTrack`. To modify notes after the
125
- * track is built, use `editor.updateClip(trackId, clipId, { midiNotes })` or
126
- * mutate the `<daw-clip>` element's `midiNotes` property directly.
127
- */
128
- midi?: {
129
- notes: MidiNoteData[];
130
- channel?: number;
131
- program?: number;
132
- };
133
- }
134
- /**
135
- * Public input shape for clips passed via `TrackConfig.clips` or
136
- * `editor.addClip(trackId, config)`. `src` is optional to support MIDI clips
137
- * with no audio source. Other fields default to the matching `<daw-clip>`
138
- * attribute defaults.
139
- */
140
- interface ClipConfig {
141
- src?: string;
142
- peaksSrc?: string;
143
- start?: number;
144
- duration?: number;
145
- offset?: number;
146
- gain?: number;
147
- name?: string;
148
- fadeIn?: number;
149
- fadeOut?: number;
150
- fadeType?: FadeType;
151
- midiNotes?: MidiNoteData[];
152
- midiChannel?: number;
153
- midiProgram?: number;
154
- }
155
-
156
49
  declare class DawTrackElement extends LitElement {
157
50
  src: string;
158
51
  name: string;
@@ -160,7 +53,9 @@ declare class DawTrackElement extends LitElement {
160
53
  pan: number;
161
54
  muted: boolean;
162
55
  soloed: boolean;
163
- renderMode: TrackRenderMode;
56
+ get renderMode(): RenderMode;
57
+ set renderMode(value: RenderMode);
58
+ private _renderMode;
164
59
  spectrogramConfig: SpectrogramConfig | null;
165
60
  readonly trackId: `${string}-${string}-${string}-${string}-${string}`;
166
61
  createRenderRoot(): this;
@@ -360,6 +255,113 @@ declare global {
360
255
  }
361
256
  }
362
257
 
258
+ type TrackRenderMode = RenderMode;
259
+ interface TrackDescriptor {
260
+ name: string;
261
+ src: string;
262
+ volume: number;
263
+ pan: number;
264
+ muted: boolean;
265
+ soloed: boolean;
266
+ renderMode: TrackRenderMode;
267
+ spectrogramConfig?: SpectrogramConfig | null;
268
+ clips: ClipDescriptor[];
269
+ }
270
+ /**
271
+ * Common fields shared by all clip descriptors regardless of source.
272
+ */
273
+ interface BaseClipDescriptor {
274
+ src: string;
275
+ peaksSrc: string;
276
+ start: number;
277
+ duration: number;
278
+ offset: number;
279
+ gain: number;
280
+ name: string;
281
+ fadeIn: number;
282
+ fadeOut: number;
283
+ fadeType: FadeType;
284
+ midiNotes: MidiNoteData[] | null;
285
+ midiChannel: number | null;
286
+ midiProgram: number | null;
287
+ }
288
+ /**
289
+ * A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
290
+ * always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
291
+ * construction. Engine `clip.id` is aligned with this id in `_loadTrack`
292
+ * and `_loadAndAppendClip` so DOM and engine reference the same clip.
293
+ */
294
+ interface DomClipDescriptor extends BaseClipDescriptor {
295
+ kind: 'dom';
296
+ clipId: string;
297
+ }
298
+ /**
299
+ * A clip descriptor synthesized from a non-DOM source — file drops, the
300
+ * `<daw-track src>` shorthand fallback, or recording-clip insertion. No
301
+ * `clipId` because there's no DOM element to align with; the engine
302
+ * generates its own id at clip-creation time.
303
+ */
304
+ interface DropClipDescriptor extends BaseClipDescriptor {
305
+ kind: 'drop';
306
+ }
307
+ type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
308
+ /**
309
+ * Type predicate for the `'dom'` discriminator. Use to narrow a
310
+ * `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
311
+ * inline `c.kind === 'dom'` repetition.
312
+ */
313
+ declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
314
+ /**
315
+ * Public input shape for `editor.addTrack(config)`. All fields optional —
316
+ * defaults match the declarative `<daw-track>` defaults.
317
+ */
318
+ interface TrackConfig {
319
+ name?: string;
320
+ volume?: number;
321
+ pan?: number;
322
+ muted?: boolean;
323
+ soloed?: boolean;
324
+ renderMode?: TrackRenderMode;
325
+ spectrogramConfig?: SpectrogramConfig | null;
326
+ clips?: ClipConfig[];
327
+ /**
328
+ * Convenience: creates a single piano-roll `<daw-clip>` child with these
329
+ * notes and sets `render-mode="piano-roll"` on the track. Equivalent to
330
+ * passing `{ renderMode: 'piano-roll', clips: [{ midiNotes, midiChannel, midiProgram }] }`.
331
+ * An explicit `renderMode` takes precedence over the inferred `'piano-roll'`.
332
+ *
333
+ * Creation-only — ignored by `updateTrack`. To modify notes after the
334
+ * track is built, use `editor.updateClip(trackId, clipId, { midiNotes })` or
335
+ * mutate the `<daw-clip>` element's `midiNotes` property directly.
336
+ */
337
+ midi?: {
338
+ notes: MidiNoteData[];
339
+ channel?: number;
340
+ program?: number;
341
+ };
342
+ }
343
+ /**
344
+ * Public input shape for clips passed via `TrackConfig.clips` or
345
+ * `editor.addClip(trackId, config)`. `src` is optional to support MIDI clips
346
+ * with no audio source. Other fields default to the matching `<daw-clip>`
347
+ * attribute defaults.
348
+ */
349
+ interface ClipConfig {
350
+ src?: string;
351
+ peaksSrc?: string;
352
+ start?: number;
353
+ duration?: number;
354
+ offset?: number;
355
+ gain?: number;
356
+ name?: string;
357
+ fadeIn?: number;
358
+ fadeOut?: number;
359
+ fadeType?: FadeType;
360
+ midiNotes?: MidiNoteData[];
361
+ midiChannel?: number;
362
+ midiProgram?: number;
363
+ }
364
+
363
365
  /**
364
366
  * Peak generation pipeline: AudioBuffer → web worker → WaveformData → PeakData.
365
367
  *
@@ -792,6 +794,12 @@ interface DawClipSplitDetail {
792
794
  }
793
795
  interface DawSpectrogramReadyDetail {
794
796
  trackId: string;
797
+ generation: number;
798
+ }
799
+ interface DawSpectrogramErrorDetail {
800
+ trackId: string;
801
+ generation: number;
802
+ error: Error;
795
803
  }
796
804
  interface DawEventMap {
797
805
  'daw-selection': CustomEvent<DawSelectionDetail>;
@@ -821,6 +829,7 @@ interface DawEventMap {
821
829
  'daw-clip-trim': CustomEvent<DawClipTrimDetail>;
822
830
  'daw-clip-split': CustomEvent<DawClipSplitDetail>;
823
831
  'daw-spectrogram-ready': CustomEvent<DawSpectrogramReadyDetail>;
832
+ 'daw-spectrogram-error': CustomEvent<DawSpectrogramErrorDetail>;
824
833
  }
825
834
  type DawEvent<K extends keyof DawEventMap> = DawEventMap[K];
826
835
  interface LoadFilesResult {
@@ -906,9 +915,10 @@ declare class DawEditorElement extends LitElement implements MidiLoaderHost {
906
915
  /** Called by <daw-spectrogram> on chunk unmount / element disconnect. */
907
916
  _spectrogramUnregisterCanvas(canvasId: string): void;
908
917
  /**
909
- * Push a clip's decoded audio into the spectrogram controller. No-op
910
- * unless the track is in spectrogram render-mode and the controller
911
- * already exists (it bootstraps from canvas registration).
918
+ * Forward a clip's AudioBuffer to the spectrogram controller if the parent
919
+ * track is in spectrogram render-mode. Eagerly creates the controller via
920
+ * `_ensureSpectrogramController` so the audio data is queued for the first
921
+ * render — even if no canvases have been registered yet.
912
922
  */
913
923
  private _maybeRegisterSpectrogramClipAudio;
914
924
  scaleMode: 'temporal' | 'beats';
@@ -1014,7 +1024,10 @@ declare class DawEditorElement extends LitElement implements MidiLoaderHost {
1014
1024
  * `_selectedTrackId`, etc.) — most of which don't affect the spectrogram
1015
1025
  * viewport. Skip the cross-controller call when nothing changed.
1016
1026
  *
1017
- * The orchestrator dedupes too, but this avoids the call entirely.
1027
+ * The orchestrator dedupes identical viewports too, so removing this cache
1028
+ * wouldn't change observable behavior — but it would push a fresh
1029
+ * `setViewport` call (with object allocation) into every Lit reactive
1030
+ * update for properties unrelated to the viewport.
1018
1031
  */
1019
1032
  private _lastSpectrogramViewport;
1020
1033
  protected updated(_changed: Map<string, unknown>): void;
@@ -1349,6 +1362,7 @@ declare class DawSpectrogramElement extends LitElement {
1349
1362
  static styles: lit.CSSResult;
1350
1363
  private _canvases;
1351
1364
  private _registeredCanvasIds;
1365
+ private _warnedNoHost;
1352
1366
  /**
1353
1367
  * Walk up to the editor host. `closest('daw-editor')` does NOT cross
1354
1368
  * shadow boundaries — and this element lives inside the editor's shadow