@dawcore/components 0.0.15 → 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 +353 -85
- package/dist/index.d.ts +353 -85
- package/dist/index.js +1202 -199
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1190 -189
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as lit from 'lit';
|
|
2
2
|
import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import { MidiNoteData, SpectrogramConfig, FadeType, Peaks, Bits, 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
|
+
import { ClipRegistration, CanvasRegistration, ViewportState } from '@dawcore/spectrogram';
|
|
6
7
|
|
|
7
8
|
declare class DawClipElement extends LitElement {
|
|
8
9
|
src: string;
|
|
@@ -16,6 +17,16 @@ declare class DawClipElement extends LitElement {
|
|
|
16
17
|
fadeIn: number;
|
|
17
18
|
fadeOut: number;
|
|
18
19
|
fadeType: string;
|
|
20
|
+
/** MIDI notes — JS property only, not reflected (note arrays are too large for attributes). */
|
|
21
|
+
midiNotes: MidiNoteData[] | null;
|
|
22
|
+
/** MIDI channel (0-indexed). Channel 9 = GM percussion. */
|
|
23
|
+
get midiChannel(): number | null;
|
|
24
|
+
set midiChannel(value: number | null);
|
|
25
|
+
private _midiChannel;
|
|
26
|
+
/** MIDI program (GM instrument 0-127). Used by SoundFontToneTrack. */
|
|
27
|
+
get midiProgram(): number | null;
|
|
28
|
+
set midiProgram(value: number | null);
|
|
29
|
+
private _midiProgram;
|
|
19
30
|
readonly clipId: `${string}-${string}-${string}-${string}-${string}`;
|
|
20
31
|
createRenderRoot(): this;
|
|
21
32
|
connectedCallback(): void;
|
|
@@ -28,6 +39,113 @@ declare global {
|
|
|
28
39
|
}
|
|
29
40
|
}
|
|
30
41
|
|
|
42
|
+
type TrackRenderMode = 'waveform' | 'piano-roll' | 'spectrogram';
|
|
43
|
+
interface TrackDescriptor {
|
|
44
|
+
name: string;
|
|
45
|
+
src: string;
|
|
46
|
+
volume: number;
|
|
47
|
+
pan: number;
|
|
48
|
+
muted: boolean;
|
|
49
|
+
soloed: boolean;
|
|
50
|
+
renderMode: TrackRenderMode;
|
|
51
|
+
spectrogramConfig?: SpectrogramConfig | null;
|
|
52
|
+
clips: ClipDescriptor[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Common fields shared by all clip descriptors regardless of source.
|
|
56
|
+
*/
|
|
57
|
+
interface BaseClipDescriptor {
|
|
58
|
+
src: string;
|
|
59
|
+
peaksSrc: string;
|
|
60
|
+
start: number;
|
|
61
|
+
duration: number;
|
|
62
|
+
offset: number;
|
|
63
|
+
gain: number;
|
|
64
|
+
name: string;
|
|
65
|
+
fadeIn: number;
|
|
66
|
+
fadeOut: number;
|
|
67
|
+
fadeType: FadeType;
|
|
68
|
+
midiNotes: MidiNoteData[] | null;
|
|
69
|
+
midiChannel: number | null;
|
|
70
|
+
midiProgram: number | null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
|
|
74
|
+
* always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
|
|
75
|
+
* construction. Engine `clip.id` is aligned with this id in `_loadTrack`
|
|
76
|
+
* and `_loadAndAppendClip` so DOM and engine reference the same clip.
|
|
77
|
+
*/
|
|
78
|
+
interface DomClipDescriptor extends BaseClipDescriptor {
|
|
79
|
+
kind: 'dom';
|
|
80
|
+
clipId: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A clip descriptor synthesized from a non-DOM source — file drops, the
|
|
84
|
+
* `<daw-track src>` shorthand fallback, or recording-clip insertion. No
|
|
85
|
+
* `clipId` because there's no DOM element to align with; the engine
|
|
86
|
+
* generates its own id at clip-creation time.
|
|
87
|
+
*/
|
|
88
|
+
interface DropClipDescriptor extends BaseClipDescriptor {
|
|
89
|
+
kind: 'drop';
|
|
90
|
+
}
|
|
91
|
+
type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
|
|
92
|
+
/**
|
|
93
|
+
* Type predicate for the `'dom'` discriminator. Use to narrow a
|
|
94
|
+
* `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
|
|
95
|
+
* inline `c.kind === 'dom'` repetition.
|
|
96
|
+
*/
|
|
97
|
+
declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
|
|
98
|
+
/**
|
|
99
|
+
* Public input shape for `editor.addTrack(config)`. All fields optional —
|
|
100
|
+
* defaults match the declarative `<daw-track>` defaults.
|
|
101
|
+
*/
|
|
102
|
+
interface TrackConfig {
|
|
103
|
+
name?: string;
|
|
104
|
+
volume?: number;
|
|
105
|
+
pan?: number;
|
|
106
|
+
muted?: boolean;
|
|
107
|
+
soloed?: boolean;
|
|
108
|
+
renderMode?: TrackRenderMode;
|
|
109
|
+
spectrogramConfig?: SpectrogramConfig | null;
|
|
110
|
+
clips?: ClipConfig[];
|
|
111
|
+
/**
|
|
112
|
+
* Convenience: creates a single piano-roll `<daw-clip>` child with these
|
|
113
|
+
* notes and sets `render-mode="piano-roll"` on the track. Equivalent to
|
|
114
|
+
* passing `{ renderMode: 'piano-roll', clips: [{ midiNotes, midiChannel, midiProgram }] }`.
|
|
115
|
+
* An explicit `renderMode` takes precedence over the inferred `'piano-roll'`.
|
|
116
|
+
*
|
|
117
|
+
* Creation-only — ignored by `updateTrack`. To modify notes after the
|
|
118
|
+
* track is built, use `editor.updateClip(trackId, clipId, { midiNotes })` or
|
|
119
|
+
* mutate the `<daw-clip>` element's `midiNotes` property directly.
|
|
120
|
+
*/
|
|
121
|
+
midi?: {
|
|
122
|
+
notes: MidiNoteData[];
|
|
123
|
+
channel?: number;
|
|
124
|
+
program?: number;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Public input shape for clips passed via `TrackConfig.clips` or
|
|
129
|
+
* `editor.addClip(trackId, config)`. `src` is optional to support MIDI clips
|
|
130
|
+
* with no audio source. Other fields default to the matching `<daw-clip>`
|
|
131
|
+
* attribute defaults.
|
|
132
|
+
*/
|
|
133
|
+
interface ClipConfig {
|
|
134
|
+
src?: string;
|
|
135
|
+
peaksSrc?: string;
|
|
136
|
+
start?: number;
|
|
137
|
+
duration?: number;
|
|
138
|
+
offset?: number;
|
|
139
|
+
gain?: number;
|
|
140
|
+
name?: string;
|
|
141
|
+
fadeIn?: number;
|
|
142
|
+
fadeOut?: number;
|
|
143
|
+
fadeType?: FadeType;
|
|
144
|
+
midiNotes?: MidiNoteData[];
|
|
145
|
+
midiChannel?: number;
|
|
146
|
+
midiProgram?: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
31
149
|
declare class DawTrackElement extends LitElement {
|
|
32
150
|
src: string;
|
|
33
151
|
name: string;
|
|
@@ -35,6 +153,8 @@ declare class DawTrackElement extends LitElement {
|
|
|
35
153
|
pan: number;
|
|
36
154
|
muted: boolean;
|
|
37
155
|
soloed: boolean;
|
|
156
|
+
renderMode: TrackRenderMode;
|
|
157
|
+
spectrogramConfig: SpectrogramConfig | null;
|
|
38
158
|
readonly trackId: `${string}-${string}-${string}-${string}-${string}`;
|
|
39
159
|
createRenderRoot(): this;
|
|
40
160
|
connectedCallback(): void;
|
|
@@ -112,6 +232,42 @@ declare global {
|
|
|
112
232
|
}
|
|
113
233
|
}
|
|
114
234
|
|
|
235
|
+
declare class DawPianoRollElement extends LitElement {
|
|
236
|
+
midiNotes: MidiNoteData[];
|
|
237
|
+
length: number;
|
|
238
|
+
waveHeight: number;
|
|
239
|
+
get samplesPerPixel(): number;
|
|
240
|
+
set samplesPerPixel(value: number);
|
|
241
|
+
private _samplesPerPixel;
|
|
242
|
+
get sampleRate(): number;
|
|
243
|
+
set sampleRate(value: number);
|
|
244
|
+
private _sampleRate;
|
|
245
|
+
clipOffsetSeconds: number;
|
|
246
|
+
/** Visible viewport start in pixels (relative to timeline origin). */
|
|
247
|
+
visibleStart: number;
|
|
248
|
+
/** Visible viewport end in pixels (relative to timeline origin). */
|
|
249
|
+
visibleEnd: number;
|
|
250
|
+
/** This element's left offset on the timeline (for viewport intersection). */
|
|
251
|
+
originX: number;
|
|
252
|
+
selected: boolean;
|
|
253
|
+
static styles: lit.CSSResult;
|
|
254
|
+
private _rafHandle;
|
|
255
|
+
private _scheduleDraw;
|
|
256
|
+
willUpdate(_changed: PropertyValues): void;
|
|
257
|
+
updated(changedProperties: Map<string, unknown>): void;
|
|
258
|
+
private _getPitchRange;
|
|
259
|
+
private _getNoteColor;
|
|
260
|
+
private _draw;
|
|
261
|
+
connectedCallback(): void;
|
|
262
|
+
disconnectedCallback(): void;
|
|
263
|
+
render(): lit.TemplateResult<1>;
|
|
264
|
+
}
|
|
265
|
+
declare global {
|
|
266
|
+
interface HTMLElementTagNameMap {
|
|
267
|
+
'daw-piano-roll': DawPianoRollElement;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
115
271
|
declare class DawPlayheadElement extends LitElement {
|
|
116
272
|
private _animation;
|
|
117
273
|
private _line;
|
|
@@ -173,6 +329,8 @@ declare class DawPauseButtonElement extends DawTransportButton {
|
|
|
173
329
|
private _targetRef;
|
|
174
330
|
private _onRecStart;
|
|
175
331
|
private _onRecEnd;
|
|
332
|
+
private _onRecPause;
|
|
333
|
+
private _onRecResume;
|
|
176
334
|
static styles: lit.CSSResultGroup[];
|
|
177
335
|
connectedCallback(): void;
|
|
178
336
|
disconnectedCallback(): void;
|
|
@@ -195,87 +353,6 @@ declare global {
|
|
|
195
353
|
}
|
|
196
354
|
}
|
|
197
355
|
|
|
198
|
-
interface TrackDescriptor {
|
|
199
|
-
name: string;
|
|
200
|
-
src: string;
|
|
201
|
-
volume: number;
|
|
202
|
-
pan: number;
|
|
203
|
-
muted: boolean;
|
|
204
|
-
soloed: boolean;
|
|
205
|
-
clips: ClipDescriptor[];
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Common fields shared by all clip descriptors regardless of source.
|
|
209
|
-
*/
|
|
210
|
-
interface BaseClipDescriptor {
|
|
211
|
-
src: string;
|
|
212
|
-
peaksSrc: string;
|
|
213
|
-
start: number;
|
|
214
|
-
duration: number;
|
|
215
|
-
offset: number;
|
|
216
|
-
gain: number;
|
|
217
|
-
name: string;
|
|
218
|
-
fadeIn: number;
|
|
219
|
-
fadeOut: number;
|
|
220
|
-
fadeType: FadeType;
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* A clip descriptor sourced from a `<daw-clip>` DOM element. `clipId` is
|
|
224
|
-
* always set — `<daw-clip>.clipId` is a `crypto.randomUUID()` generated at
|
|
225
|
-
* construction. Engine `clip.id` is aligned with this id in `_loadTrack`
|
|
226
|
-
* and `_loadAndAppendClip` so DOM and engine reference the same clip.
|
|
227
|
-
*/
|
|
228
|
-
interface DomClipDescriptor extends BaseClipDescriptor {
|
|
229
|
-
kind: 'dom';
|
|
230
|
-
clipId: string;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* A clip descriptor synthesized from a non-DOM source — file drops, the
|
|
234
|
-
* `<daw-track src>` shorthand fallback, or recording-clip insertion. No
|
|
235
|
-
* `clipId` because there's no DOM element to align with; the engine
|
|
236
|
-
* generates its own id at clip-creation time.
|
|
237
|
-
*/
|
|
238
|
-
interface DropClipDescriptor extends BaseClipDescriptor {
|
|
239
|
-
kind: 'drop';
|
|
240
|
-
}
|
|
241
|
-
type ClipDescriptor = DomClipDescriptor | DropClipDescriptor;
|
|
242
|
-
/**
|
|
243
|
-
* Type predicate for the `'dom'` discriminator. Use to narrow a
|
|
244
|
-
* `ClipDescriptor` to `DomClipDescriptor` (which has `clipId`) without
|
|
245
|
-
* inline `c.kind === 'dom'` repetition.
|
|
246
|
-
*/
|
|
247
|
-
declare function isDomClip(desc: ClipDescriptor): desc is DomClipDescriptor;
|
|
248
|
-
/**
|
|
249
|
-
* Public input shape for `editor.addTrack(config)`. All fields optional —
|
|
250
|
-
* defaults match the declarative `<daw-track>` defaults.
|
|
251
|
-
*/
|
|
252
|
-
interface TrackConfig {
|
|
253
|
-
name?: string;
|
|
254
|
-
volume?: number;
|
|
255
|
-
pan?: number;
|
|
256
|
-
muted?: boolean;
|
|
257
|
-
soloed?: boolean;
|
|
258
|
-
clips?: ClipConfig[];
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Public input shape for clips passed via `TrackConfig.clips` or
|
|
262
|
-
* `editor.addClip(trackId, config)`. `src` is required — every clip needs
|
|
263
|
-
* an audio source to load. Other fields default to the matching
|
|
264
|
-
* `<daw-clip>` attribute defaults.
|
|
265
|
-
*/
|
|
266
|
-
interface ClipConfig {
|
|
267
|
-
src: string;
|
|
268
|
-
peaksSrc?: string;
|
|
269
|
-
start?: number;
|
|
270
|
-
duration?: number;
|
|
271
|
-
offset?: number;
|
|
272
|
-
gain?: number;
|
|
273
|
-
name?: string;
|
|
274
|
-
fadeIn?: number;
|
|
275
|
-
fadeOut?: number;
|
|
276
|
-
fadeType?: FadeType;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
356
|
/**
|
|
280
357
|
* Peak generation pipeline: AudioBuffer → web worker → WaveformData → PeakData.
|
|
281
358
|
*
|
|
@@ -434,6 +511,12 @@ interface RecordingSession {
|
|
|
434
511
|
/** Stored so it can be removed on stop/cleanup — not just when stream ends. */
|
|
435
512
|
readonly _onTrackEnded: (() => void) | null;
|
|
436
513
|
readonly _audioTrack: MediaStreamTrack | null;
|
|
514
|
+
/** Set during stopRecording, cleared by the done message from the worklet. */
|
|
515
|
+
stopAckResolve: (() => void) | null;
|
|
516
|
+
/** True from the start of stopRecording until the session is deleted.
|
|
517
|
+
* Guards pauseRecording / resumeRecording so a mid-drain pause toggle
|
|
518
|
+
* can't dispatch events for a session that's already terminating. */
|
|
519
|
+
stopping: boolean;
|
|
437
520
|
}
|
|
438
521
|
/** Readonly view of a recording session for external consumers. */
|
|
439
522
|
type ReadonlyRecordingSession = Readonly<Omit<RecordingSession, 'chunks' | 'peaks' | '_onTrackEnded' | '_audioTrack' | 'latencySamples'>> & {
|
|
@@ -475,16 +558,21 @@ declare class RecordingController implements ReactiveController {
|
|
|
475
558
|
private _host;
|
|
476
559
|
private _sessions;
|
|
477
560
|
private _workletLoadedCtx;
|
|
561
|
+
/** Tracks worklet pause state explicitly so external consumers (editor,
|
|
562
|
+
* pause button, spacebar) can share one source of truth. */
|
|
563
|
+
private _isPaused;
|
|
478
564
|
constructor(host: RecordingHost & HTMLElement);
|
|
479
565
|
hostConnected(): void;
|
|
480
566
|
hostDisconnected(): void;
|
|
481
567
|
get isRecording(): boolean;
|
|
568
|
+
get isPaused(): boolean;
|
|
482
569
|
getSession(trackId: string): ReadonlyRecordingSession | undefined;
|
|
483
570
|
startRecording(stream: MediaStream, options?: RecordingOptions): Promise<void>;
|
|
484
571
|
pauseRecording(trackId?: string): void;
|
|
485
572
|
resumeRecording(trackId?: string): void;
|
|
486
|
-
stopRecording(trackId?: string): void
|
|
573
|
+
stopRecording(trackId?: string): Promise<void>;
|
|
487
574
|
private _onWorkletMessage;
|
|
575
|
+
private _processWorkletSamples;
|
|
488
576
|
private _createClipFromRecording;
|
|
489
577
|
private _removeTrackEndedListener;
|
|
490
578
|
private _cleanupSession;
|
|
@@ -538,6 +626,11 @@ interface ClipPointerHost {
|
|
|
538
626
|
dispatchEvent(event: Event): boolean;
|
|
539
627
|
/** Re-extract peaks for a clip at new offset/duration from cached WaveformData. */
|
|
540
628
|
reextractClipPeaks(clipId: string, offsetSamples: number, durationSamples: number): ClipPeakSlice | null;
|
|
629
|
+
/**
|
|
630
|
+
* Returns true if the clip is a MIDI clip (has midiNotes).
|
|
631
|
+
* Trim handles are inert for MIDI clips — note slicing is not yet implemented.
|
|
632
|
+
*/
|
|
633
|
+
isMidiClip(trackId: string, clipId: string): boolean;
|
|
541
634
|
}
|
|
542
635
|
/**
|
|
543
636
|
* Handles pointer interactions for clip move and trim drag operations.
|
|
@@ -646,6 +739,12 @@ interface DawRecordingErrorDetail {
|
|
|
646
739
|
trackId: string;
|
|
647
740
|
error: unknown;
|
|
648
741
|
}
|
|
742
|
+
interface DawRecordingPauseDetail {
|
|
743
|
+
trackId: string;
|
|
744
|
+
}
|
|
745
|
+
interface DawRecordingResumeDetail {
|
|
746
|
+
trackId: string;
|
|
747
|
+
}
|
|
649
748
|
interface DawClipConnectedDetail {
|
|
650
749
|
clipId: string;
|
|
651
750
|
element: DawClipElement;
|
|
@@ -684,6 +783,9 @@ interface DawClipSplitDetail {
|
|
|
684
783
|
readonly leftClipId: string;
|
|
685
784
|
readonly rightClipId: string;
|
|
686
785
|
}
|
|
786
|
+
interface DawSpectrogramReadyDetail {
|
|
787
|
+
trackId: string;
|
|
788
|
+
}
|
|
687
789
|
interface DawEventMap {
|
|
688
790
|
'daw-selection': CustomEvent<DawSelectionDetail>;
|
|
689
791
|
'daw-seek': CustomEvent<DawSeekDetail>;
|
|
@@ -702,6 +804,8 @@ interface DawEventMap {
|
|
|
702
804
|
'daw-recording-start': CustomEvent<DawRecordingStartDetail>;
|
|
703
805
|
'daw-recording-complete': CustomEvent<DawRecordingCompleteDetail>;
|
|
704
806
|
'daw-recording-error': CustomEvent<DawRecordingErrorDetail>;
|
|
807
|
+
'daw-recording-pause': CustomEvent<DawRecordingPauseDetail>;
|
|
808
|
+
'daw-recording-resume': CustomEvent<DawRecordingResumeDetail>;
|
|
705
809
|
'daw-clip-connected': CustomEvent<DawClipConnectedDetail>;
|
|
706
810
|
'daw-clip-update': CustomEvent<DawClipUpdateDetail>;
|
|
707
811
|
'daw-clip-ready': CustomEvent<DawClipIdDetail>;
|
|
@@ -709,6 +813,7 @@ interface DawEventMap {
|
|
|
709
813
|
'daw-clip-move': CustomEvent<DawClipMoveDetail>;
|
|
710
814
|
'daw-clip-trim': CustomEvent<DawClipTrimDetail>;
|
|
711
815
|
'daw-clip-split': CustomEvent<DawClipSplitDetail>;
|
|
816
|
+
'daw-spectrogram-ready': CustomEvent<DawSpectrogramReadyDetail>;
|
|
712
817
|
}
|
|
713
818
|
type DawEvent<K extends keyof DawEventMap> = DawEventMap[K];
|
|
714
819
|
interface LoadFilesResult {
|
|
@@ -739,6 +844,44 @@ declare class DawEditorElement extends LitElement {
|
|
|
739
844
|
* floor already provides this; this attribute controls the temporal mode.
|
|
740
845
|
*/
|
|
741
846
|
indefinitePlayback: boolean;
|
|
847
|
+
/**
|
|
848
|
+
* Default spectrogram FFT/render config inherited by tracks with
|
|
849
|
+
* `render-mode="spectrogram"` that do not set their own. Wired into the
|
|
850
|
+
* orchestrator by `SpectrogramController` in Task 14.
|
|
851
|
+
*/
|
|
852
|
+
get spectrogramConfig(): SpectrogramConfig | null;
|
|
853
|
+
set spectrogramConfig(value: SpectrogramConfig | null);
|
|
854
|
+
private _spectrogramConfig;
|
|
855
|
+
/**
|
|
856
|
+
* Default color map for spectrogram tracks. Tracks may override via
|
|
857
|
+
* their own per-track property in a future iteration. Separate from
|
|
858
|
+
* `spectrogramConfig` because `ColorMapValue` is not part of the
|
|
859
|
+
* `SpectrogramConfig` shape.
|
|
860
|
+
*/
|
|
861
|
+
get spectrogramColorMap(): ColorMapValue | null;
|
|
862
|
+
set spectrogramColorMap(value: ColorMapValue | null);
|
|
863
|
+
private _spectrogramColorMap;
|
|
864
|
+
private _ensureSpectrogramController;
|
|
865
|
+
/** Called by <daw-spectrogram> after transferControlToOffscreen. */
|
|
866
|
+
_spectrogramRegisterCanvas(reg: {
|
|
867
|
+
canvasId: string;
|
|
868
|
+
canvas: OffscreenCanvas;
|
|
869
|
+
clipId: string;
|
|
870
|
+
trackId: string;
|
|
871
|
+
channelIndex: number;
|
|
872
|
+
chunkIndex: number;
|
|
873
|
+
globalPixelOffset: number;
|
|
874
|
+
widthPx: number;
|
|
875
|
+
heightPx: number;
|
|
876
|
+
}): void;
|
|
877
|
+
/** Called by <daw-spectrogram> on chunk unmount / element disconnect. */
|
|
878
|
+
_spectrogramUnregisterCanvas(canvasId: string): void;
|
|
879
|
+
/**
|
|
880
|
+
* Push a clip's decoded audio into the spectrogram controller. No-op
|
|
881
|
+
* unless the track is in spectrogram render-mode and the controller
|
|
882
|
+
* already exists (it bootstraps from canvas registration).
|
|
883
|
+
*/
|
|
884
|
+
private _maybeRegisterSpectrogramClipAudio;
|
|
742
885
|
scaleMode: 'temporal' | 'beats';
|
|
743
886
|
get ticksPerPixel(): number;
|
|
744
887
|
set ticksPerPixel(value: number);
|
|
@@ -795,12 +938,19 @@ declare class DawEditorElement extends LitElement {
|
|
|
795
938
|
private _audioResume;
|
|
796
939
|
eagerResume?: string;
|
|
797
940
|
private _recordingController;
|
|
941
|
+
private _spectrogramController;
|
|
798
942
|
private _clipPointer;
|
|
799
943
|
get _clipHandler(): ClipPointerHandler | null;
|
|
800
944
|
get engine(): PlaylistEngine | null;
|
|
801
945
|
get renderSamplesPerPixel(): number;
|
|
802
946
|
/** Re-extract peaks for a clip at new offset/duration from cached WaveformData. */
|
|
803
947
|
reextractClipPeaks(clipId: string, offsetSamples: number, durationSamples: number): PeakData | null;
|
|
948
|
+
/**
|
|
949
|
+
* Returns true if the clip is a MIDI clip (has midiNotes).
|
|
950
|
+
* Used by ClipPointerHandler to make trim handles inert for MIDI clips.
|
|
951
|
+
* Returns false for unknown track/clip IDs (defensive).
|
|
952
|
+
*/
|
|
953
|
+
isMidiClip(trackId: string, clipId: string): boolean;
|
|
804
954
|
private _pointer;
|
|
805
955
|
private _viewport;
|
|
806
956
|
static styles: lit.CSSResult[];
|
|
@@ -829,9 +979,12 @@ declare class DawEditorElement extends LitElement {
|
|
|
829
979
|
connectedCallback(): void;
|
|
830
980
|
disconnectedCallback(): void;
|
|
831
981
|
willUpdate(changedProperties: Map<string, unknown>): void;
|
|
982
|
+
protected updated(_changed: Map<string, unknown>): void;
|
|
832
983
|
private _onTrackConnected;
|
|
833
984
|
private _onTrackRemoved;
|
|
834
985
|
private _onTrackUpdate;
|
|
986
|
+
/** Drop the controller when no spectrogram tracks remain. */
|
|
987
|
+
private _disposeSpectrogramControllerIfEmpty;
|
|
835
988
|
private static _CONTROL_PROPS;
|
|
836
989
|
private _onTrackControl;
|
|
837
990
|
private _onTrackRemoveRequest;
|
|
@@ -859,6 +1012,27 @@ declare class DawEditorElement extends LitElement {
|
|
|
859
1012
|
* uses sync `extractPeaks` and inserts a preview track BEFORE audio decode.
|
|
860
1013
|
*/
|
|
861
1014
|
private _finalizeAudioClip;
|
|
1015
|
+
/**
|
|
1016
|
+
* Filter MIDI notes to only those with finite, in-range fields. Logs a
|
|
1017
|
+
* warning for each dropped note. Used by _buildMidiClip and the
|
|
1018
|
+
* _applyClipUpdate MIDI branch to prevent NaN propagation through the
|
|
1019
|
+
* timeline.
|
|
1020
|
+
*/
|
|
1021
|
+
private _validMidiNotes;
|
|
1022
|
+
/**
|
|
1023
|
+
* A clip descriptor is treated as MIDI when it has no audio src.
|
|
1024
|
+
* Includes placeholder MIDI clips (no notes, no duration yet — registered
|
|
1025
|
+
* with a 1s default span; notes upgrade via _applyClipUpdate). Warns when
|
|
1026
|
+
* a clip ambiguously has both src and midiNotes — the audio path runs
|
|
1027
|
+
* and notes would be silently ignored.
|
|
1028
|
+
*/
|
|
1029
|
+
private _isMidiDescriptor;
|
|
1030
|
+
/**
|
|
1031
|
+
* Build an engine clip from a MIDI clip descriptor. Always returns a clip
|
|
1032
|
+
* — empty notes / no declared duration get a 1-second placeholder span so
|
|
1033
|
+
* the clip is reachable via `engine.updateTrack` once notes arrive.
|
|
1034
|
+
*/
|
|
1035
|
+
private _buildMidiClip;
|
|
862
1036
|
/** Remove a single clip from all per-clip caches. Used by error rollbacks. */
|
|
863
1037
|
private _purgeClipCaches;
|
|
864
1038
|
/**
|
|
@@ -963,9 +1137,20 @@ declare class DawEditorElement extends LitElement {
|
|
|
963
1137
|
recordingStream: MediaStream | null;
|
|
964
1138
|
get currentTime(): number;
|
|
965
1139
|
get isRecording(): boolean;
|
|
1140
|
+
get isRecordingPaused(): boolean;
|
|
966
1141
|
pauseRecording(): void;
|
|
967
1142
|
resumeRecording(): void;
|
|
968
|
-
|
|
1143
|
+
/**
|
|
1144
|
+
* Audacity-style pause toggle for active recordings: pauses both the
|
|
1145
|
+
* worklet capture and (if running) the playback Transport. On resume,
|
|
1146
|
+
* Transport restarts only if it was running before — non-overdub
|
|
1147
|
+
* recordings stay silent on resume.
|
|
1148
|
+
*/
|
|
1149
|
+
togglePauseRecording(): void;
|
|
1150
|
+
/** Set in togglePauseRecording when Transport is paused alongside the
|
|
1151
|
+
* worklet, so resume can restart it. Cleared on resume and on stop. */
|
|
1152
|
+
private _wasPlayingDuringRecording;
|
|
1153
|
+
stopRecording(): Promise<void>;
|
|
969
1154
|
_addRecordedClip(trackId: string, buf: AudioBuffer, startSample: number, durSamples: number, offsetSamples?: number): void;
|
|
970
1155
|
addWorkletModule(url: string): Promise<void>;
|
|
971
1156
|
createAudioWorkletNode(name: string, options?: AudioWorkletNodeOptions): AudioWorkletNode;
|
|
@@ -1093,6 +1278,89 @@ declare global {
|
|
|
1093
1278
|
}
|
|
1094
1279
|
}
|
|
1095
1280
|
|
|
1281
|
+
declare class DawSpectrogramElement extends LitElement {
|
|
1282
|
+
clipId: string;
|
|
1283
|
+
trackId: string;
|
|
1284
|
+
channelIndex: number;
|
|
1285
|
+
length: number;
|
|
1286
|
+
waveHeight: number;
|
|
1287
|
+
get samplesPerPixel(): number;
|
|
1288
|
+
set samplesPerPixel(value: number);
|
|
1289
|
+
private _samplesPerPixel;
|
|
1290
|
+
get sampleRate(): number;
|
|
1291
|
+
set sampleRate(value: number);
|
|
1292
|
+
private _sampleRate;
|
|
1293
|
+
clipOffsetSeconds: number;
|
|
1294
|
+
visibleStart: number;
|
|
1295
|
+
visibleEnd: number;
|
|
1296
|
+
originX: number;
|
|
1297
|
+
static styles: lit.CSSResult;
|
|
1298
|
+
private _canvases;
|
|
1299
|
+
private _registeredCanvasIds;
|
|
1300
|
+
/**
|
|
1301
|
+
* Walk up to the editor host. `closest('daw-editor')` does NOT cross
|
|
1302
|
+
* shadow boundaries — and this element lives inside the editor's shadow
|
|
1303
|
+
* DOM — so use getRootNode().host to step out.
|
|
1304
|
+
*/
|
|
1305
|
+
private _findHostEditor;
|
|
1306
|
+
willUpdate(changed: PropertyValues): void;
|
|
1307
|
+
private _rebuildChunks;
|
|
1308
|
+
protected updated(_changed: PropertyValues): void;
|
|
1309
|
+
private _registerCanvases;
|
|
1310
|
+
private _unregisterAllCanvases;
|
|
1311
|
+
disconnectedCallback(): void;
|
|
1312
|
+
render(): lit.TemplateResult<1>;
|
|
1313
|
+
}
|
|
1314
|
+
declare global {
|
|
1315
|
+
interface HTMLElementTagNameMap {
|
|
1316
|
+
'daw-spectrogram': DawSpectrogramElement;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
interface SpectrogramControllerHost extends ReactiveControllerHost {
|
|
1321
|
+
dispatchEvent(event: Event): boolean;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Lit reactive controller that owns a `SpectrogramOrchestrator` for the
|
|
1325
|
+
* `<daw-editor>` host. Creates the orchestrator lazily on first canvas
|
|
1326
|
+
* registration so editors without spectrogram tracks pay nothing.
|
|
1327
|
+
*
|
|
1328
|
+
* Holds editor-level defaults and per-track overrides separately; merges
|
|
1329
|
+
* them down to a single (config, colorMap) pair for the orchestrator on
|
|
1330
|
+
* each change.
|
|
1331
|
+
*
|
|
1332
|
+
* v1 limitation: orchestrator accepts ONE config / colorMap at a time, so
|
|
1333
|
+
* the "first registered track wins" rule applies when multiple tracks are
|
|
1334
|
+
* in spectrogram mode with different overrides. Multi-track per-clip
|
|
1335
|
+
* configs are deferred to a follow-up.
|
|
1336
|
+
*/
|
|
1337
|
+
declare class SpectrogramController implements ReactiveController {
|
|
1338
|
+
private host;
|
|
1339
|
+
private workerFactory;
|
|
1340
|
+
private orchestrator;
|
|
1341
|
+
private editorConfig;
|
|
1342
|
+
private editorColorMap;
|
|
1343
|
+
private trackConfigs;
|
|
1344
|
+
private trackColorMaps;
|
|
1345
|
+
constructor(host: SpectrogramControllerHost, workerFactory: () => Worker);
|
|
1346
|
+
hostConnected(): void;
|
|
1347
|
+
hostDisconnected(): void;
|
|
1348
|
+
setEditorConfig(config: SpectrogramConfig | null): void;
|
|
1349
|
+
setEditorColorMap(colorMap: ColorMapValue | null): void;
|
|
1350
|
+
setTrackConfig(trackId: string, config: SpectrogramConfig | null): void;
|
|
1351
|
+
setTrackColorMap(trackId: string, colorMap: ColorMapValue | null): void;
|
|
1352
|
+
registerClipAudio(reg: ClipRegistration): void;
|
|
1353
|
+
unregisterClipAudio(clipId: string): void;
|
|
1354
|
+
registerCanvas(reg: CanvasRegistration): void;
|
|
1355
|
+
unregisterCanvas(canvasId: string): void;
|
|
1356
|
+
setViewport(state: ViewportState): void;
|
|
1357
|
+
dispose(): void;
|
|
1358
|
+
private ensureOrchestrator;
|
|
1359
|
+
private reapply;
|
|
1360
|
+
private mergedConfig;
|
|
1361
|
+
private mergedColorMap;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1096
1364
|
interface AudioResumeHost extends ReactiveControllerHost, HTMLElement {
|
|
1097
1365
|
/** Returns the AudioContext to resume on user gesture */
|
|
1098
1366
|
readonly audioContext: AudioContext;
|
|
@@ -1149,4 +1417,4 @@ interface SplitHost {
|
|
|
1149
1417
|
*/
|
|
1150
1418
|
declare function splitAtPlayhead(host: SplitHost): boolean;
|
|
1151
1419
|
|
|
1152
|
-
export { AudioResumeController, type ClipConfig, type ClipDescriptor, type ClipEngineContract, ClipPointerHandler, type ClipPointerHost, type DawClipConnectedDetail, DawClipElement, type DawClipErrorDetail, type DawClipIdDetail, type DawClipMoveDetail, type DawClipSplitDetail, type DawClipTrimDetail, type DawClipUpdateDetail, DawEditorElement, type DawErrorDetail, type DawEvent, type DawEventMap, type DawFilesLoadErrorDetail, DawGridElement, DawKeyboardShortcutsElement, DawPauseButtonElement, DawPlayButtonElement, DawPlayheadElement, DawRecordButtonElement, type DawRecordingCompleteDetail, type DawRecordingErrorDetail, type DawRecordingStartDetail, DawRulerElement, type DawSeekDetail, type DawSelectionDetail, DawSelectionElement, DawStopButtonElement, type DawTrackConnectedDetail, type DawTrackControlDetail, DawTrackControlsElement, DawTrackElement, type DawTrackErrorDetail, type DawTrackIdDetail, type DawTrackRemoveDetail, type DawTrackSelectDetail, DawTransportButton, DawTransportElement, DawWaveformElement, type DomClipDescriptor, type DropClipDescriptor, type KeyBinding, type LoadFilesResult, type PlaybackShortcutMap, type PointerEngineContract, RecordingController, type RecordingOptions, type RecordingSession, type SplitEngineContract, type SplitHost, type SplittingShortcutMap, type TrackConfig, type TrackDescriptor, type UndoShortcutMap, type WaveformSegment, isDomClip, splitAtPlayhead };
|
|
1420
|
+
export { AudioResumeController, type ClipConfig, type ClipDescriptor, type ClipEngineContract, ClipPointerHandler, type ClipPointerHost, type DawClipConnectedDetail, DawClipElement, type DawClipErrorDetail, type DawClipIdDetail, type DawClipMoveDetail, type DawClipSplitDetail, type DawClipTrimDetail, type DawClipUpdateDetail, DawEditorElement, type DawErrorDetail, type DawEvent, type DawEventMap, type DawFilesLoadErrorDetail, DawGridElement, DawKeyboardShortcutsElement, DawPauseButtonElement, DawPianoRollElement, DawPlayButtonElement, DawPlayheadElement, DawRecordButtonElement, type DawRecordingCompleteDetail, type DawRecordingErrorDetail, type DawRecordingStartDetail, DawRulerElement, type DawSeekDetail, type DawSelectionDetail, DawSelectionElement, DawSpectrogramElement, DawStopButtonElement, type DawTrackConnectedDetail, type DawTrackControlDetail, DawTrackControlsElement, DawTrackElement, type DawTrackErrorDetail, type DawTrackIdDetail, type DawTrackRemoveDetail, type DawTrackSelectDetail, DawTransportButton, DawTransportElement, DawWaveformElement, type DomClipDescriptor, type DropClipDescriptor, type KeyBinding, type LoadFilesResult, type PlaybackShortcutMap, type PointerEngineContract, RecordingController, type RecordingOptions, type RecordingSession, SpectrogramController, type SplitEngineContract, type SplitHost, type SplittingShortcutMap, type TrackConfig, type TrackDescriptor, type TrackRenderMode, type UndoShortcutMap, type WaveformSegment, isDomClip, splitAtPlayhead };
|