@dawcore/components 0.0.5 → 0.0.8
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/README.md +292 -0
- package/dist/index.d.mts +16 -10
- package/dist/index.d.ts +16 -10
- package/dist/index.js +71 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# @dawcore/components
|
|
2
|
+
|
|
3
|
+
Framework-agnostic Web Components for multi-track audio editing. Drop `<daw-editor>` into any HTML page — no React, no build step required.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Pure Web Components** — Works with vanilla HTML, React, Vue, Svelte, or any framework
|
|
8
|
+
- **Declarative tracks** — `<daw-track>` and `<daw-clip>` elements define your timeline in HTML
|
|
9
|
+
- **Canvas waveforms** — Chunked rendering with virtual scrolling for large timelines
|
|
10
|
+
- **Drag interactions** — Move clips, trim boundaries, split at playhead
|
|
11
|
+
- **Keyboard shortcuts** — Play/pause, split, undo/redo via `<daw-keyboard-shortcuts>`
|
|
12
|
+
- **Undo/redo** — Full transaction-based undo with Cmd/Ctrl+Z and Cmd/Ctrl+Shift+Z
|
|
13
|
+
- **File drop** — Drag audio files onto the editor to add tracks
|
|
14
|
+
- **Recording** — Live mic recording with waveform preview, pause/resume, cancelable clip creation
|
|
15
|
+
- **Pre-computed peaks** — Instant waveform rendering from `.dat` files before audio decodes
|
|
16
|
+
- **Track controls** — Volume, pan, mute, solo per track via `<daw-track-controls>`
|
|
17
|
+
- **Transport access** — Tempo, metronome, count-in, meter, effects via `@dawcore/transport`
|
|
18
|
+
- **CSS theming** — Dark mode by default, fully customizable via CSS custom properties
|
|
19
|
+
- **Native Web Audio** — Uses `@dawcore/transport` for playback scheduling. No Tone.js dependency.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @dawcore/components
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Peer dependencies:
|
|
28
|
+
```bash
|
|
29
|
+
npm install @waveform-playlist/core @waveform-playlist/engine @dawcore/transport
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Optional (for recording):
|
|
33
|
+
```bash
|
|
34
|
+
npm install @waveform-playlist/recording @waveform-playlist/worklets
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<script type="module">
|
|
41
|
+
import '@dawcore/components';
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<daw-editor id="editor" samples-per-pixel="1024" wave-height="100" timescale>
|
|
45
|
+
<daw-track src="/audio/drums.opus" name="Drums"></daw-track>
|
|
46
|
+
<daw-track src="/audio/bass.opus" name="Bass"></daw-track>
|
|
47
|
+
<daw-track src="/audio/synth.opus" name="Synth"></daw-track>
|
|
48
|
+
</daw-editor>
|
|
49
|
+
|
|
50
|
+
<daw-transport for="editor">
|
|
51
|
+
<daw-play-button></daw-play-button>
|
|
52
|
+
<daw-pause-button></daw-pause-button>
|
|
53
|
+
<daw-stop-button></daw-stop-button>
|
|
54
|
+
</daw-transport>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That's it. The editor loads audio, generates waveforms, and handles playback.
|
|
58
|
+
|
|
59
|
+
## Multi-Clip Timeline
|
|
60
|
+
|
|
61
|
+
For multiple clips per track with independent positioning:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<daw-editor id="editor" samples-per-pixel="1024" wave-height="80"
|
|
65
|
+
timescale clip-headers interactive-clips>
|
|
66
|
+
<daw-keyboard-shortcuts playback splitting undo></daw-keyboard-shortcuts>
|
|
67
|
+
|
|
68
|
+
<daw-track name="Drums">
|
|
69
|
+
<daw-clip src="/audio/drums.opus" start="0" duration="8"></daw-clip>
|
|
70
|
+
<daw-clip src="/audio/drums.opus" start="12" duration="8" offset="8"></daw-clip>
|
|
71
|
+
</daw-track>
|
|
72
|
+
|
|
73
|
+
<daw-track name="Bass">
|
|
74
|
+
<daw-clip src="/audio/bass.opus" start="0" duration="20"></daw-clip>
|
|
75
|
+
</daw-track>
|
|
76
|
+
</daw-editor>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Pre-Computed Peaks
|
|
80
|
+
|
|
81
|
+
For instant waveform rendering before audio finishes decoding:
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<daw-track name="Drums">
|
|
85
|
+
<daw-clip src="/audio/drums.opus"
|
|
86
|
+
peaks-src="/audio/drums.dat"
|
|
87
|
+
start="0" duration="8"></daw-clip>
|
|
88
|
+
</daw-track>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The `.dat` file renders the waveform immediately. Audio decodes in the background for playback.
|
|
92
|
+
|
|
93
|
+
## Transport Access
|
|
94
|
+
|
|
95
|
+
Access the native transport for tempo, metronome, count-in, meter, and effects:
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const editor = document.getElementById('editor');
|
|
99
|
+
|
|
100
|
+
// Transport is available after first track loads
|
|
101
|
+
editor.addEventListener('daw-play', () => {
|
|
102
|
+
const transport = editor.engine?.adapter?.transport;
|
|
103
|
+
if (!transport) return;
|
|
104
|
+
|
|
105
|
+
// Tempo & meter
|
|
106
|
+
transport.setTempo(140);
|
|
107
|
+
transport.setMeter(3, 4);
|
|
108
|
+
|
|
109
|
+
// Metronome (default click sounds built in)
|
|
110
|
+
transport.setMetronomeEnabled(true);
|
|
111
|
+
|
|
112
|
+
// Count-in
|
|
113
|
+
transport.setCountIn(true);
|
|
114
|
+
transport.setCountInBars(1);
|
|
115
|
+
transport.setCountInMode('always');
|
|
116
|
+
|
|
117
|
+
transport.on('countIn', ({ beat, totalBeats }) => {
|
|
118
|
+
console.log(beat + '/' + totalBeats);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Effects hook — insert any AudioNode chain
|
|
122
|
+
transport.connectTrackOutput('track-id', reverbNode);
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Programmatic File Loading
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const editor = document.getElementById('editor');
|
|
130
|
+
const result = await editor.loadFiles(fileList);
|
|
131
|
+
// result: { loaded: string[], failed: Array<{ file, error }> }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Recording
|
|
135
|
+
|
|
136
|
+
```html
|
|
137
|
+
<daw-editor id="editor" samples-per-pixel="1024" wave-height="100">
|
|
138
|
+
<daw-track name="Recording"></daw-track>
|
|
139
|
+
</daw-editor>
|
|
140
|
+
|
|
141
|
+
<daw-transport for="editor">
|
|
142
|
+
<daw-play-button></daw-play-button>
|
|
143
|
+
<daw-pause-button></daw-pause-button>
|
|
144
|
+
<daw-stop-button></daw-stop-button>
|
|
145
|
+
<daw-record-button></daw-record-button>
|
|
146
|
+
</daw-transport>
|
|
147
|
+
|
|
148
|
+
<script type="module">
|
|
149
|
+
const editor = document.getElementById('editor');
|
|
150
|
+
// Consumer provides the mic stream
|
|
151
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
152
|
+
audio: { channelCount: { ideal: 2 } } // request stereo when available
|
|
153
|
+
});
|
|
154
|
+
editor.recordingStream = stream;
|
|
155
|
+
|
|
156
|
+
// Cancelable — prevent default to handle the AudioBuffer yourself
|
|
157
|
+
editor.addEventListener('daw-recording-complete', (e) => {
|
|
158
|
+
// e.preventDefault(); // skip automatic clip creation
|
|
159
|
+
console.log('recorded:', e.detail.audioBuffer);
|
|
160
|
+
});
|
|
161
|
+
</script>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Keyboard Shortcuts
|
|
165
|
+
|
|
166
|
+
Add `<daw-keyboard-shortcuts>` as a child of `<daw-editor>`:
|
|
167
|
+
|
|
168
|
+
```html
|
|
169
|
+
<daw-editor id="editor">
|
|
170
|
+
<daw-keyboard-shortcuts playback splitting undo></daw-keyboard-shortcuts>
|
|
171
|
+
<!-- ... tracks ... -->
|
|
172
|
+
</daw-editor>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Attribute | Shortcuts |
|
|
176
|
+
|-----------|-----------|
|
|
177
|
+
| `playback` | Space (play/pause), Enter (stop) |
|
|
178
|
+
| `splitting` | S (split at playhead) |
|
|
179
|
+
| `undo` | Cmd/Ctrl+Z (undo), Cmd/Ctrl+Shift+Z (redo) |
|
|
180
|
+
|
|
181
|
+
Custom shortcuts via JS properties: `playbackShortcuts`, `splittingShortcuts`, `undoShortcuts`, `customShortcuts`.
|
|
182
|
+
|
|
183
|
+
## CSS Theming
|
|
184
|
+
|
|
185
|
+
Style with CSS custom properties on `<daw-editor>` or any ancestor:
|
|
186
|
+
|
|
187
|
+
```css
|
|
188
|
+
daw-editor {
|
|
189
|
+
--daw-wave-color: #c49a6c;
|
|
190
|
+
--daw-playhead-color: #d08070;
|
|
191
|
+
--daw-background: #1a1a2e;
|
|
192
|
+
--daw-track-background: #16213e;
|
|
193
|
+
--daw-ruler-color: #c49a6c;
|
|
194
|
+
--daw-ruler-background: #0f0f1a;
|
|
195
|
+
--daw-selection-color: rgba(99, 199, 95, 0.3);
|
|
196
|
+
--daw-controls-background: #1a1a2e;
|
|
197
|
+
--daw-controls-text: #e0d4c8;
|
|
198
|
+
--daw-clip-header-background: rgba(0, 0, 0, 0.4);
|
|
199
|
+
--daw-clip-header-text: #e0d4c8;
|
|
200
|
+
--daw-controls-width: 180px;
|
|
201
|
+
--daw-min-height: 200px;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Elements
|
|
206
|
+
|
|
207
|
+
### `<daw-editor>`
|
|
208
|
+
|
|
209
|
+
Core orchestrator. Attributes:
|
|
210
|
+
|
|
211
|
+
| Attribute | Type | Default | Description |
|
|
212
|
+
|-----------|------|---------|-------------|
|
|
213
|
+
| `samples-per-pixel` | number | `1024` | Zoom level |
|
|
214
|
+
| `sample-rate` | number | `48000` | AudioContext sample rate hint |
|
|
215
|
+
| `wave-height` | number | `100` | Track waveform height in pixels |
|
|
216
|
+
| `timescale` | boolean | `false` | Show time ruler |
|
|
217
|
+
| `clip-headers` | boolean | `false` | Show clip name headers |
|
|
218
|
+
| `interactive-clips` | boolean | `false` | Enable drag/trim/split |
|
|
219
|
+
| `mono` | boolean | `false` | Merge stereo to mono display |
|
|
220
|
+
| `eager-resume` | boolean | `false` | Resume AudioContext on first user gesture |
|
|
221
|
+
|
|
222
|
+
JS properties: `audioContext`, `recordingStream`, `engine`.
|
|
223
|
+
|
|
224
|
+
Methods: `loadFiles(fileList)`, `splitAtPlayhead()`.
|
|
225
|
+
|
|
226
|
+
### `<daw-track>`
|
|
227
|
+
|
|
228
|
+
Declarative track data. Attributes: `src`, `name`, `volume`, `pan`, `muted`, `soloed`, `mono`.
|
|
229
|
+
|
|
230
|
+
### `<daw-clip>`
|
|
231
|
+
|
|
232
|
+
Declarative clip data. Attributes: `src`, `peaks-src`, `start`, `duration`, `offset`, `gain`.
|
|
233
|
+
|
|
234
|
+
### `<daw-transport for="editor-id">`
|
|
235
|
+
|
|
236
|
+
Container that resolves target editor. Children: `<daw-play-button>`, `<daw-pause-button>`, `<daw-stop-button>`, `<daw-record-button>`.
|
|
237
|
+
|
|
238
|
+
### `<daw-track-controls>`
|
|
239
|
+
|
|
240
|
+
Per-track UI for volume, pan, mute, solo. Receives state from editor, dispatches `daw-track-control` and `daw-track-remove` events.
|
|
241
|
+
|
|
242
|
+
### `<daw-keyboard-shortcuts>`
|
|
243
|
+
|
|
244
|
+
Render-less child of `<daw-editor>`. Boolean attributes: `playback`, `splitting`, `undo`.
|
|
245
|
+
|
|
246
|
+
## Events
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
const editor = document.getElementById('editor');
|
|
250
|
+
|
|
251
|
+
// Playback
|
|
252
|
+
editor.addEventListener('daw-play', () => {});
|
|
253
|
+
editor.addEventListener('daw-pause', () => {});
|
|
254
|
+
editor.addEventListener('daw-stop', () => {});
|
|
255
|
+
editor.addEventListener('daw-seek', (e) => console.log(e.detail.time));
|
|
256
|
+
|
|
257
|
+
// Selection & tracks
|
|
258
|
+
editor.addEventListener('daw-selection', (e) => console.log(e.detail));
|
|
259
|
+
editor.addEventListener('daw-track-select', (e) => console.log(e.detail.trackId));
|
|
260
|
+
|
|
261
|
+
// Clip interactions
|
|
262
|
+
editor.addEventListener('daw-clip-move', (e) => console.log(e.detail));
|
|
263
|
+
editor.addEventListener('daw-clip-trim', (e) => console.log(e.detail));
|
|
264
|
+
editor.addEventListener('daw-clip-split', (e) => console.log(e.detail));
|
|
265
|
+
|
|
266
|
+
// Recording
|
|
267
|
+
editor.addEventListener('daw-recording-start', (e) => console.log(e.detail));
|
|
268
|
+
editor.addEventListener('daw-recording-complete', (e) => {
|
|
269
|
+
// e.preventDefault() to skip automatic clip creation
|
|
270
|
+
console.log(e.detail.audioBuffer);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Errors
|
|
274
|
+
editor.addEventListener('daw-track-error', (e) => console.error(e.detail));
|
|
275
|
+
editor.addEventListener('daw-error', (e) => console.error(e.detail));
|
|
276
|
+
editor.addEventListener('daw-files-load-error', (e) => console.error(e.detail));
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Custom AudioContext
|
|
280
|
+
|
|
281
|
+
By default, `<daw-editor>` creates its own `AudioContext` using the `sample-rate` attribute. To provide your own:
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
const editor = document.getElementById('editor');
|
|
285
|
+
editor.audioContext = new AudioContext({ sampleRate: 48000, latencyHint: 0 });
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Set this before tracks load. The provided context is used for decoding, playback, and recording.
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -278,6 +278,8 @@ declare global {
|
|
|
278
278
|
interface RecordingOptions {
|
|
279
279
|
trackId?: string;
|
|
280
280
|
bits?: 8 | 16;
|
|
281
|
+
/** Fallback channel count when stream doesn't report one via getSettings(). Must be 1 or 2. */
|
|
282
|
+
channelCount?: 1 | 2;
|
|
281
283
|
startSample?: number;
|
|
282
284
|
/** Start playback during recording so user hears existing tracks. */
|
|
283
285
|
overdub?: boolean;
|
|
@@ -300,7 +302,7 @@ interface RecordingSession {
|
|
|
300
302
|
readonly channelCount: number;
|
|
301
303
|
readonly bits: Bits;
|
|
302
304
|
isFirstMessage: boolean;
|
|
303
|
-
/** Latency samples to skip in live preview (outputLatency
|
|
305
|
+
/** Latency samples to skip in live preview (outputLatency only). */
|
|
304
306
|
readonly latencySamples: number;
|
|
305
307
|
readonly wasOverdub: boolean;
|
|
306
308
|
/** Stored so it can be removed on stop/cleanup — not just when stream ends. */
|
|
@@ -315,6 +317,7 @@ type ReadonlyRecordingSession = Readonly<Omit<RecordingSession, 'chunks' | 'peak
|
|
|
315
317
|
};
|
|
316
318
|
/** Narrow interface for the host editor. */
|
|
317
319
|
interface RecordingHost extends ReactiveControllerHost {
|
|
320
|
+
readonly audioContext: AudioContext;
|
|
318
321
|
readonly samplesPerPixel: number;
|
|
319
322
|
readonly effectiveSampleRate: number;
|
|
320
323
|
readonly _selectedTrackId: string | null;
|
|
@@ -329,7 +332,7 @@ interface RecordingHost extends ReactiveControllerHost {
|
|
|
329
332
|
declare class RecordingController implements ReactiveController {
|
|
330
333
|
private _host;
|
|
331
334
|
private _sessions;
|
|
332
|
-
private
|
|
335
|
+
private _workletLoadedCtx;
|
|
333
336
|
constructor(host: RecordingHost & HTMLElement);
|
|
334
337
|
hostConnected(): void;
|
|
335
338
|
hostDisconnected(): void;
|
|
@@ -562,6 +565,12 @@ declare class DawEditorElement extends LitElement {
|
|
|
562
565
|
_selectionStartTime: number;
|
|
563
566
|
_selectionEndTime: number;
|
|
564
567
|
_currentTime: number;
|
|
568
|
+
/** Consumer-provided AudioContext. When set, used for decode, playback, and recording. */
|
|
569
|
+
private _externalAudioContext;
|
|
570
|
+
private _ownedAudioContext;
|
|
571
|
+
/** Set an AudioContext to use for all audio operations. Must be set before tracks load. */
|
|
572
|
+
set audioContext(ctx: AudioContext | null);
|
|
573
|
+
get audioContext(): AudioContext;
|
|
565
574
|
_engine: PlaylistEngine | null;
|
|
566
575
|
private _enginePromise;
|
|
567
576
|
_audioCache: Map<string, Promise<AudioBuffer>>;
|
|
@@ -612,13 +621,6 @@ declare class DawEditorElement extends LitElement {
|
|
|
612
621
|
private _onTrackRemoveRequest;
|
|
613
622
|
private _readTrackDescriptor;
|
|
614
623
|
private _loadTrack;
|
|
615
|
-
private _contextConfigurePromise;
|
|
616
|
-
/**
|
|
617
|
-
* Ensure the global AudioContext is configured with the editor's sample-rate hint
|
|
618
|
-
* before the first audio operation. Idempotent — concurrent callers await the
|
|
619
|
-
* same promise so no one proceeds to getGlobalAudioContext() before configuration.
|
|
620
|
-
*/
|
|
621
|
-
private _ensureContextConfigured;
|
|
622
624
|
_fetchAndDecode(src: string): Promise<AudioBuffer>;
|
|
623
625
|
private _fetchPeaks;
|
|
624
626
|
_recomputeDuration(): void;
|
|
@@ -769,6 +771,10 @@ declare global {
|
|
|
769
771
|
}
|
|
770
772
|
}
|
|
771
773
|
|
|
774
|
+
interface AudioResumeHost extends ReactiveControllerHost, HTMLElement {
|
|
775
|
+
/** Returns the AudioContext to resume on user gesture */
|
|
776
|
+
readonly audioContext: AudioContext;
|
|
777
|
+
}
|
|
772
778
|
declare class AudioResumeController implements ReactiveController {
|
|
773
779
|
private _host;
|
|
774
780
|
private _target;
|
|
@@ -776,7 +782,7 @@ declare class AudioResumeController implements ReactiveController {
|
|
|
776
782
|
private _generation;
|
|
777
783
|
/** CSS selector, or 'document'. When undefined, controller is inert. */
|
|
778
784
|
target?: string;
|
|
779
|
-
constructor(host:
|
|
785
|
+
constructor(host: AudioResumeHost);
|
|
780
786
|
hostConnected(): void;
|
|
781
787
|
hostDisconnected(): void;
|
|
782
788
|
private _onGesture;
|
package/dist/index.d.ts
CHANGED
|
@@ -278,6 +278,8 @@ declare global {
|
|
|
278
278
|
interface RecordingOptions {
|
|
279
279
|
trackId?: string;
|
|
280
280
|
bits?: 8 | 16;
|
|
281
|
+
/** Fallback channel count when stream doesn't report one via getSettings(). Must be 1 or 2. */
|
|
282
|
+
channelCount?: 1 | 2;
|
|
281
283
|
startSample?: number;
|
|
282
284
|
/** Start playback during recording so user hears existing tracks. */
|
|
283
285
|
overdub?: boolean;
|
|
@@ -300,7 +302,7 @@ interface RecordingSession {
|
|
|
300
302
|
readonly channelCount: number;
|
|
301
303
|
readonly bits: Bits;
|
|
302
304
|
isFirstMessage: boolean;
|
|
303
|
-
/** Latency samples to skip in live preview (outputLatency
|
|
305
|
+
/** Latency samples to skip in live preview (outputLatency only). */
|
|
304
306
|
readonly latencySamples: number;
|
|
305
307
|
readonly wasOverdub: boolean;
|
|
306
308
|
/** Stored so it can be removed on stop/cleanup — not just when stream ends. */
|
|
@@ -315,6 +317,7 @@ type ReadonlyRecordingSession = Readonly<Omit<RecordingSession, 'chunks' | 'peak
|
|
|
315
317
|
};
|
|
316
318
|
/** Narrow interface for the host editor. */
|
|
317
319
|
interface RecordingHost extends ReactiveControllerHost {
|
|
320
|
+
readonly audioContext: AudioContext;
|
|
318
321
|
readonly samplesPerPixel: number;
|
|
319
322
|
readonly effectiveSampleRate: number;
|
|
320
323
|
readonly _selectedTrackId: string | null;
|
|
@@ -329,7 +332,7 @@ interface RecordingHost extends ReactiveControllerHost {
|
|
|
329
332
|
declare class RecordingController implements ReactiveController {
|
|
330
333
|
private _host;
|
|
331
334
|
private _sessions;
|
|
332
|
-
private
|
|
335
|
+
private _workletLoadedCtx;
|
|
333
336
|
constructor(host: RecordingHost & HTMLElement);
|
|
334
337
|
hostConnected(): void;
|
|
335
338
|
hostDisconnected(): void;
|
|
@@ -562,6 +565,12 @@ declare class DawEditorElement extends LitElement {
|
|
|
562
565
|
_selectionStartTime: number;
|
|
563
566
|
_selectionEndTime: number;
|
|
564
567
|
_currentTime: number;
|
|
568
|
+
/** Consumer-provided AudioContext. When set, used for decode, playback, and recording. */
|
|
569
|
+
private _externalAudioContext;
|
|
570
|
+
private _ownedAudioContext;
|
|
571
|
+
/** Set an AudioContext to use for all audio operations. Must be set before tracks load. */
|
|
572
|
+
set audioContext(ctx: AudioContext | null);
|
|
573
|
+
get audioContext(): AudioContext;
|
|
565
574
|
_engine: PlaylistEngine | null;
|
|
566
575
|
private _enginePromise;
|
|
567
576
|
_audioCache: Map<string, Promise<AudioBuffer>>;
|
|
@@ -612,13 +621,6 @@ declare class DawEditorElement extends LitElement {
|
|
|
612
621
|
private _onTrackRemoveRequest;
|
|
613
622
|
private _readTrackDescriptor;
|
|
614
623
|
private _loadTrack;
|
|
615
|
-
private _contextConfigurePromise;
|
|
616
|
-
/**
|
|
617
|
-
* Ensure the global AudioContext is configured with the editor's sample-rate hint
|
|
618
|
-
* before the first audio operation. Idempotent — concurrent callers await the
|
|
619
|
-
* same promise so no one proceeds to getGlobalAudioContext() before configuration.
|
|
620
|
-
*/
|
|
621
|
-
private _ensureContextConfigured;
|
|
622
624
|
_fetchAndDecode(src: string): Promise<AudioBuffer>;
|
|
623
625
|
private _fetchPeaks;
|
|
624
626
|
_recomputeDuration(): void;
|
|
@@ -769,6 +771,10 @@ declare global {
|
|
|
769
771
|
}
|
|
770
772
|
}
|
|
771
773
|
|
|
774
|
+
interface AudioResumeHost extends ReactiveControllerHost, HTMLElement {
|
|
775
|
+
/** Returns the AudioContext to resume on user gesture */
|
|
776
|
+
readonly audioContext: AudioContext;
|
|
777
|
+
}
|
|
772
778
|
declare class AudioResumeController implements ReactiveController {
|
|
773
779
|
private _host;
|
|
774
780
|
private _target;
|
|
@@ -776,7 +782,7 @@ declare class AudioResumeController implements ReactiveController {
|
|
|
776
782
|
private _generation;
|
|
777
783
|
/** CSS selector, or 'document'. When undefined, controller is inert. */
|
|
778
784
|
target?: string;
|
|
779
|
-
constructor(host:
|
|
785
|
+
constructor(host: AudioResumeHost);
|
|
780
786
|
hostConnected(): void;
|
|
781
787
|
hostDisconnected(): void;
|
|
782
788
|
private _onGesture;
|