@dawcore/components 0.0.23 → 0.0.24
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 +155 -16
- package/dist/index.d.mts +248 -1
- package/dist/index.d.ts +248 -1
- package/dist/index.js +1269 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1266 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -7
package/README.md
CHANGED
|
@@ -10,11 +10,16 @@ Framework-agnostic Web Components for multi-track audio editing. Drop `<daw-edit
|
|
|
10
10
|
- **Drag interactions** — Move clips, trim boundaries, split at playhead
|
|
11
11
|
- **Keyboard shortcuts** — Play/pause, split, undo/redo via `<daw-keyboard-shortcuts>`
|
|
12
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
|
|
13
|
+
- **File drop** — Drag audio files onto the editor to add tracks (enable with the `file-drop` attribute)
|
|
14
14
|
- **Recording** — Live mic recording with waveform preview, pause/resume, cancelable clip creation
|
|
15
15
|
- **Pre-computed peaks** — Instant waveform rendering from `.dat` files before audio decodes
|
|
16
|
-
- **MIDI tracks** —
|
|
16
|
+
- **MIDI tracks** — Declarative or programmatic MIDI clips render as piano-roll. Playback via the Tone.js adapter. See [MIDI Tracks](#midi-tracks).
|
|
17
|
+
- **MIDI file loading** — `editor.loadMidi(urlOrFile)` parses a `.mid` file into piano-roll tracks via the optional `@dawcore/midi` peer
|
|
18
|
+
- **Spectrogram rendering** — `<daw-track render-mode="spectrogram">` renders FFT spectrograms via `@dawcore/spectrogram`
|
|
17
19
|
- **Track controls** — Volume, pan, mute, solo per track via `<daw-track-controls>`
|
|
20
|
+
- **Effects chains** — Per-track and master effect chains with built-in `native-*` effects, WAM 2.0 plugins via `@dawcore/wam`, and in-browser-compiled Faust DSP via `@dawcore/faust`. See [Effects](#effects).
|
|
21
|
+
- **Effect GUIs and persistence** — Mount plugin GUIs into your own panels; snapshot and restore whole chains. See [Effect GUIs](#effect-guis) and [Effects Persistence](#effects-persistence).
|
|
22
|
+
- **Offline export** — `editor.exportAudio()` renders the session (clips, mix, all effect chains) to an `AudioBuffer`. See [Offline Export](#offline-export).
|
|
18
23
|
- **Transport access** — Tempo, metronome, count-in, meter, effects via `@dawcore/transport`
|
|
19
24
|
- **CSS theming** — Dark mode by default, fully customizable via CSS custom properties
|
|
20
25
|
- **Native Web Audio** — Uses `@dawcore/transport` for playback scheduling. No Tone.js dependency.
|
|
@@ -25,21 +30,27 @@ Framework-agnostic Web Components for multi-track audio editing. Drop `<daw-edit
|
|
|
25
30
|
npm install @dawcore/components
|
|
26
31
|
```
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
Required peer dependencies:
|
|
34
|
+
|
|
29
35
|
```bash
|
|
30
36
|
npm install @waveform-playlist/core @waveform-playlist/engine
|
|
31
37
|
```
|
|
32
38
|
|
|
33
39
|
Audio backend (choose one — see [Choosing an Audio Backend](#choosing-an-audio-backend)):
|
|
40
|
+
|
|
34
41
|
```bash
|
|
35
42
|
npm install @dawcore/transport # Native Web Audio (recommended)
|
|
36
43
|
# or
|
|
37
44
|
npm install @waveform-playlist/playout tone # Tone.js
|
|
38
45
|
```
|
|
39
46
|
|
|
40
|
-
Optional (
|
|
47
|
+
Optional peer dependencies — each is dynamic-imported on first use, so you only install (and ship) what you use:
|
|
48
|
+
|
|
41
49
|
```bash
|
|
42
|
-
npm install @waveform-playlist/worklets
|
|
50
|
+
npm install @waveform-playlist/worklets # recording
|
|
51
|
+
npm install @dawcore/midi # editor.loadMidi()
|
|
52
|
+
npm install @dawcore/wam # WAM 2.0 plugins (addWamPlugin) + generic effect GUIs
|
|
53
|
+
npm install @dawcore/faust @dawcore/wam # in-browser Faust compilation (addFaustEffect)
|
|
43
54
|
```
|
|
44
55
|
|
|
45
56
|
## Quick Start
|
|
@@ -93,7 +104,7 @@ adapter.transport.setCountIn(true);
|
|
|
93
104
|
|
|
94
105
|
### Tone.js (effects, MIDI synths)
|
|
95
106
|
|
|
96
|
-
Uses Tone.js for audio processing. Single tempo/meter only. **Required for MIDI playback** — the native adapter has no MIDI synth
|
|
107
|
+
Uses Tone.js for audio processing. Single tempo/meter only. **Required for MIDI playback** — the native adapter has no MIDI synth, so MIDI clips render as piano-roll but play silently on it.
|
|
97
108
|
|
|
98
109
|
```bash
|
|
99
110
|
npm install @waveform-playlist/playout tone
|
|
@@ -128,7 +139,7 @@ For multiple clips per track with independent positioning:
|
|
|
128
139
|
|
|
129
140
|
## MIDI Tracks
|
|
130
141
|
|
|
131
|
-
Programmatic MIDI clips render as piano-roll. Playback requires the Tone.js adapter (the native adapter has no MIDI synth
|
|
142
|
+
Programmatic MIDI clips render as piano-roll. Playback requires the Tone.js adapter (the native adapter has no MIDI synth). Use the `editor.addTrack({ midi })` sugar for the simplest path:
|
|
132
143
|
|
|
133
144
|
```javascript
|
|
134
145
|
import { createToneAdapter } from '@waveform-playlist/playout';
|
|
@@ -164,7 +175,7 @@ This expands to a `<daw-track render-mode="piano-roll">` containing a `<daw-clip
|
|
|
164
175
|
</script>
|
|
165
176
|
```
|
|
166
177
|
|
|
167
|
-
A clip is treated as MIDI iff `clip.midiNotes != null`. MIDI clips skip audio fetch + decode + peak generation.
|
|
178
|
+
A clip is treated as MIDI iff `clip.midiNotes != null`. MIDI clips skip audio fetch + decode + peak generation. Move drag works on MIDI clips; trim handles and split-at-playhead are inert on them.
|
|
168
179
|
|
|
169
180
|
**Theming:** the piano-roll honors `--daw-piano-roll-note-color` (default `#2a7070`), `--daw-piano-roll-selected-note-color` (default `#3d9e9e`), and `--daw-piano-roll-background` (default `#1a1a2e`).
|
|
170
181
|
|
|
@@ -184,6 +195,24 @@ For instant waveform rendering before audio finishes decoding:
|
|
|
184
195
|
|
|
185
196
|
The `.dat` file renders the waveform immediately. Audio decodes in the background for playback.
|
|
186
197
|
|
|
198
|
+
## Effects Persistence
|
|
199
|
+
|
|
200
|
+
`getEffectsState()` / `setEffectsState(entries)` on `<daw-editor>` (master chain) and `<daw-track>` snapshot and restore effect chains. Persist the returned array however you like (localStorage, server, project file):
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
const saved = await editor.getEffectsState();
|
|
204
|
+
// [
|
|
205
|
+
// { kind: 'native', type: 'native-delay', params: {...}, bypassed: false },
|
|
206
|
+
// { kind: 'wam', url: 'https://…/index.js', bypassed: false, state: {…} },
|
|
207
|
+
// ]
|
|
208
|
+
localStorage.setItem('master-fx', JSON.stringify(saved));
|
|
209
|
+
|
|
210
|
+
// later / next session
|
|
211
|
+
await editor.setEffectsState(JSON.parse(localStorage.getItem('master-fx')));
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
WAM entries carry the plugin's own `getState()` snapshot, reapplied on restore. Faust entries (added with `addFaustEffect`) persist their DSP source instead of a URL — `{ kind: 'wam', faustDsp, faustName, bypassed, state }` — and are recompiled in the browser on restore. If a saved plugin URL is unreachable (or a saved Faust source no longer compiles), the restore **continues**: the entry becomes a bypassed passthrough placeholder at its saved position (a `daw-effect-error` event fires with `{effectId, url?, source?, message}`), and its saved state is retained so re-serializing round-trips it for a later retry.
|
|
215
|
+
|
|
187
216
|
## Transport Access
|
|
188
217
|
|
|
189
218
|
Transport-specific APIs are on the `NativePlayoutAdapter` reference:
|
|
@@ -202,6 +231,88 @@ adapter.transport.on('countIn', ({ beat, totalBeats }) => {
|
|
|
202
231
|
adapter.transport.connectTrackOutput('track-id', reverbNode);
|
|
203
232
|
```
|
|
204
233
|
|
|
234
|
+
## Effects
|
|
235
|
+
|
|
236
|
+
Per-track and master effect chains (requires `@dawcore/transport` >= 0.0.13). `<daw-track>` owns its track chain; `<daw-editor>` owns the master chain — same API on both:
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
const track = document.querySelector('daw-track');
|
|
240
|
+
|
|
241
|
+
// Built-in native-* effects: native-gain, native-filter, native-compressor,
|
|
242
|
+
// native-stereo-panner, native-delay
|
|
243
|
+
const filterId = track.addEffect('native-filter', { frequency: 800 });
|
|
244
|
+
const compressorId = editor.addEffect('native-compressor'); // master chain
|
|
245
|
+
|
|
246
|
+
track.setEffectParams(filterId, { frequency: 2000 }); // live, during playback
|
|
247
|
+
track.setEffectBypassed(filterId, true);
|
|
248
|
+
track.moveEffect(filterId, 1);
|
|
249
|
+
track.removeEffect(filterId);
|
|
250
|
+
console.log(track.effects); // [{ id, kind, type, params, bypassed }, ...]
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Effect events dispatch from the owning element and bubble to the editor:
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
editor.addEventListener('daw-effect-add', (e) => console.log(e.detail));
|
|
257
|
+
// also: daw-effect-remove, daw-effect-change, daw-effect-bypass, daw-effect-reorder
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Register custom effects with `registerEffect(type, definition)`; inspect built-ins with `getEffectDefinitions()` (exports from `@dawcore/components`).
|
|
261
|
+
|
|
262
|
+
### WAM Plugins
|
|
263
|
+
|
|
264
|
+
[Web Audio Modules 2.0](https://www.webaudiomodules.com/) plugins load into the same chains via the optional `@dawcore/wam` peer (`npm install @dawcore/wam`):
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
const wamId = await track.addWamPlugin('https://www.webaudiomodules.com/community/plugins/burns-audio/delay/index.js');
|
|
268
|
+
// WAM entries are ordinary chain entries — bypass/move/remove/events all work
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
See `examples/dawcore-native/effects.html` for a native-effects demo and `examples/dawcore-wam/` (`pnpm example:dawcore-wam`) for the end-to-end WAM demo: URL paste, community-library picker (`fetchWamLibrary`), GUIs, persistence with reload, and WAV export.
|
|
272
|
+
|
|
273
|
+
### Faust Effects (compiled in the browser)
|
|
274
|
+
|
|
275
|
+
Write custom DSP in [Faust](https://faust.grame.fr/) and hear it instantly — `addFaustEffect(dspCode, options?)` compiles the source **in the browser** via the optional `@dawcore/faust` peer (`npm install @dawcore/faust @dawcore/wam`) and adds the result to the chain as an ordinary WAM entry:
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
// Track chains are stereo — duplicate mono filters across both channels.
|
|
279
|
+
const effectId = await track.addFaustEffect(
|
|
280
|
+
`import("stdfaust.lib");
|
|
281
|
+
cutoff = hslider("cutoff", 1000, 20, 20000, 1);
|
|
282
|
+
process = fi.lowpass(2, cutoff), fi.lowpass(2, cutoff);`,
|
|
283
|
+
{ name: 'My Lowpass' }
|
|
284
|
+
);
|
|
285
|
+
// Every hslider/vslider/checkbox becomes a WAM parameter + a GUI control.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The Faust compiler (~2.5 MB gzipped WASM) loads lazily on the first call — consumers who never compile Faust load zero compiler bytes. Compile errors keep Faust's line/column diagnostics and leave the chain untouched. Faust entries persist as their DSP source (`{ kind: 'wam', faustDsp, faustName, state }` — no URL) and are **recompiled** on `setEffectsState` restore and offline export. See the "Faust (compile in browser)" section of `examples/dawcore-wam/`.
|
|
289
|
+
|
|
290
|
+
### Effect GUIs
|
|
291
|
+
|
|
292
|
+
`openEffectGui(effectId, container)` / `closeEffectGui(effectId)` on both elements mount an effect's GUI into a container **you** provide (your own panel, drawer, floating window — dawcore ships no plugin-window UI):
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
const panel = document.querySelector('#fx-panel');
|
|
296
|
+
|
|
297
|
+
const guiEl = await track.openEffectGui(wamId, panel); // WAM plugins mount their own GUI
|
|
298
|
+
track.closeEffectGui(wamId); // hides — audio keeps processing, element stays cached
|
|
299
|
+
await track.openEffectGui(wamId, panel); // instant reopen, same element
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The GUI is created lazily on first open and only destroyed (`destroyGui`) when the effect — or its track — is removed from the chain. Plugins without a GUI, and `native-*` effects, get a generic parameter panel (labeled sliders from the plugin's `getParameterInfo()` or the registry's params metadata) rendered by `@dawcore/wam`; slider edits apply live and dispatch `daw-effect-change` like any other parameter edit.
|
|
303
|
+
|
|
304
|
+
### Offline Export
|
|
305
|
+
|
|
306
|
+
`editor.exportAudio(options?)` renders the whole session — clips, volume/pan, mute/solo, per-track and master effect chains — on an `OfflineAudioContext` and resolves to an `AudioBuffer` (encode it to WAV/FLAC however you like):
|
|
307
|
+
|
|
308
|
+
```javascript
|
|
309
|
+
const buffer = await editor.exportAudio();
|
|
310
|
+
// options: { sampleRate?, startTime?, duration?, channels? }
|
|
311
|
+
const intro = await editor.exportAudio({ startTime: 0, duration: 8, channels: 2 });
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Chains rebuild from their persisted form: `native-*` effects via the registry, WAM plugins re-instantiated on the offline context with their saved state (worklets are bound to one context), and Faust entries recompiled from their persisted DSP source. Bypass behavior matches live playback; all offline plugin instances are destroyed after rendering.
|
|
315
|
+
|
|
205
316
|
## Programmatic File Loading
|
|
206
317
|
|
|
207
318
|
```javascript
|
|
@@ -292,26 +403,39 @@ Core orchestrator. Attributes:
|
|
|
292
403
|
|
|
293
404
|
| Attribute | Type | Default | Description |
|
|
294
405
|
|-----------|------|---------|-------------|
|
|
295
|
-
| `samples-per-pixel` | number | `1024` | Zoom level |
|
|
296
|
-
| `
|
|
297
|
-
| `wave-height` | number | `100` | Track waveform height in pixels |
|
|
406
|
+
| `samples-per-pixel` | number | `1024` | Zoom level (clamped to the pre-computed peaks floor when one is active) |
|
|
407
|
+
| `wave-height` | number | `128` | Track waveform height in pixels |
|
|
298
408
|
| `timescale` | boolean | `false` | Show time ruler |
|
|
299
409
|
| `clip-headers` | boolean | `false` | Show clip name headers |
|
|
410
|
+
| `clip-header-height` | number | `20` | Clip header height in pixels |
|
|
300
411
|
| `interactive-clips` | boolean | `false` | Enable drag/trim/split |
|
|
412
|
+
| `file-drop` | boolean | `false` | Accept audio files dropped onto the editor |
|
|
301
413
|
| `mono` | boolean | `false` | Merge stereo to mono display |
|
|
302
|
-
| `
|
|
414
|
+
| `bar-width` / `bar-gap` | number | `1` / `0` | Waveform bar rendering style |
|
|
415
|
+
| `indefinite-playback` | boolean | `false` | Keep ruler/timeline filling the viewport with no clips |
|
|
416
|
+
| `scale-mode` | string | `'temporal'` | `'temporal'` (seconds) or `'beats'` (tick-linear grid) |
|
|
417
|
+
| `ticks-per-pixel` | number | `24` | Zoom level in beats mode |
|
|
418
|
+
| `snap-to` | string | `'off'` | Grid snapping in beats mode (`'bar'`, `'beat'`, `'1/2'`…`'1/16'`, `'off'`) |
|
|
419
|
+
| `eager-resume` | string | — | Resume AudioContext on first gesture; bare attribute targets the editor, or pass `"document"` / a CSS selector |
|
|
420
|
+
|
|
421
|
+
JS properties: `adapter` (required `PlayoutAdapter`), `recordingStream`, `bpm`, `ppqn`, `timeSignature`, `meterEntries`, `secondsToTicks` / `ticksToSeconds` (variable-tempo callbacks), `spectrogramConfig`, `spectrogramColorMap`. Read-only: `engine`, `audioContext` (from the adapter), `tracks`, `selection`, `selectedTrackId`, `currentTime`, `canUndo` / `canRedo`, `isRecording`.
|
|
303
422
|
|
|
304
|
-
|
|
423
|
+
Methods:
|
|
305
424
|
|
|
306
|
-
|
|
425
|
+
- Playback: `play(startTime?)`, `pause()`, `stop()`, `togglePlayPause()`, `seekTo(time)`
|
|
426
|
+
- Loading: `loadFiles(files)`, `loadMidi(urlOrFile, options?)`, `ready()`
|
|
427
|
+
- Tracks & clips: `addTrack(config)`, `removeTrack(id)`, `updateTrack(id, partial)`, `addClip(trackId, config)`, `removeClip(trackId, clipId)`, `updateClip(trackId, clipId, partial)`
|
|
428
|
+
- Editing: `splitAtPlayhead()`, `undo()`, `redo()`, `setSelection(start, end)`
|
|
429
|
+
- Recording: `startRecording(stream?, options?)`, `stopRecording()`, `pauseRecording()`, `resumeRecording()`, `togglePauseRecording()`
|
|
430
|
+
- Effects & export: the master-chain effects API (see [Effects](#effects)), `getEffectsState()` / `setEffectsState(entries)`, `openEffectGui()` / `closeEffectGui()`, `exportAudio(options?)`
|
|
307
431
|
|
|
308
432
|
### `<daw-track>`
|
|
309
433
|
|
|
310
|
-
Declarative track data. Attributes: `src`, `name`, `volume`, `pan`, `muted`, `soloed`, `
|
|
434
|
+
Declarative track data. Attributes: `src`, `name`, `volume`, `pan`, `muted`, `soloed`, `render-mode` (`'waveform' | 'piano-roll' | 'spectrogram'`, default `'waveform'`). JS property: `spectrogramConfig` (per-track spectrogram override). Also exposes the per-track effects API (see [Effects](#effects)).
|
|
311
435
|
|
|
312
436
|
### `<daw-clip>`
|
|
313
437
|
|
|
314
|
-
Declarative clip data. Attributes: `src`, `peaks-src`, `start`, `duration`, `offset`, `gain`, `midi-channel`, `midi-program`. JS-only property: `midiNotes: MidiNoteData[] | null` (note arrays are too large for attributes).
|
|
438
|
+
Declarative clip data. Attributes: `src`, `peaks-src`, `start`, `duration`, `offset`, `gain`, `name`, `color`, `midi-channel`, `midi-program`. JS-only property: `midiNotes: MidiNoteData[] | null` (note arrays are too large for attributes).
|
|
315
439
|
|
|
316
440
|
### `<daw-piano-roll>`
|
|
317
441
|
|
|
@@ -356,12 +480,20 @@ editor.addEventListener('daw-recording-complete', (e) => {
|
|
|
356
480
|
console.log(e.detail.audioBuffer);
|
|
357
481
|
});
|
|
358
482
|
|
|
483
|
+
// Effects (track events bubble up to the editor)
|
|
484
|
+
editor.addEventListener('daw-effect-add', (e) => console.log(e.detail));
|
|
485
|
+
editor.addEventListener('daw-effect-change', (e) => console.log(e.detail));
|
|
486
|
+
// also: daw-effect-remove, daw-effect-bypass, daw-effect-reorder
|
|
487
|
+
|
|
359
488
|
// Errors
|
|
360
489
|
editor.addEventListener('daw-track-error', (e) => console.error(e.detail));
|
|
361
490
|
editor.addEventListener('daw-error', (e) => console.error(e.detail));
|
|
362
491
|
editor.addEventListener('daw-files-load-error', (e) => console.error(e.detail));
|
|
492
|
+
editor.addEventListener('daw-effect-error', (e) => console.error(e.detail));
|
|
363
493
|
```
|
|
364
494
|
|
|
495
|
+
All events and their `detail` payloads are typed in the exported `DawEventMap`.
|
|
496
|
+
|
|
365
497
|
## Custom AudioContext
|
|
366
498
|
|
|
367
499
|
Pass a custom `AudioContext` via the adapter:
|
|
@@ -374,6 +506,13 @@ editor.adapter = adapter;
|
|
|
374
506
|
|
|
375
507
|
Set the adapter before tracks load. The provided context is used for decoding, playback, and recording.
|
|
376
508
|
|
|
509
|
+
## Examples & Documentation
|
|
510
|
+
|
|
511
|
+
- [`examples/dawcore-native/`](https://github.com/naomiaro/waveform-playlist/tree/main/examples/dawcore-native) — native transport: basics, multi-clip, metronome, beats grid, beat maps, effects, spectrogram, recording (`pnpm example:dawcore-native`)
|
|
512
|
+
- [`examples/dawcore-tone/`](https://github.com/naomiaro/waveform-playlist/tree/main/examples/dawcore-tone) — Tone.js adapter: MIDI, SoundFont playback (`pnpm example:dawcore-tone`)
|
|
513
|
+
- [`examples/dawcore-wam/`](https://github.com/naomiaro/waveform-playlist/tree/main/examples/dawcore-wam) — WAM plugins end-to-end + in-browser Faust compilation (`pnpm example:dawcore-wam`)
|
|
514
|
+
- Guides: [naomiaro.github.io/waveform-playlist](https://naomiaro.github.io/waveform-playlist/docs/web-components/getting-started)
|
|
515
|
+
|
|
377
516
|
## License
|
|
378
517
|
|
|
379
518
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -46,6 +46,87 @@ declare global {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/** Range/display metadata for one effect parameter. */
|
|
50
|
+
interface EffectParamDef {
|
|
51
|
+
min: number;
|
|
52
|
+
max: number;
|
|
53
|
+
step?: number;
|
|
54
|
+
/** 's', 'ms', 'Hz', 'dB', '%' … */
|
|
55
|
+
unit?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A live, wired effect. `input`/`output` are the chain attachment points
|
|
59
|
+
* (the same node for single-node effects). `applyParams` updates AudioParams
|
|
60
|
+
* in place — the chain never rebuilds for parameter changes.
|
|
61
|
+
*/
|
|
62
|
+
interface EffectInstance {
|
|
63
|
+
input: AudioNode;
|
|
64
|
+
output: AudioNode;
|
|
65
|
+
applyParams: (params: Record<string, number>) => void;
|
|
66
|
+
dispose?: () => void;
|
|
67
|
+
/** Serializable snapshot of plugin-internal state (WAM getState). */
|
|
68
|
+
getState?: () => Promise<unknown>;
|
|
69
|
+
/** Builds the plugin's own GUI element (WAM createGui). GUI lifecycle is
|
|
70
|
+
* independent of audio — hiding/destroying a GUI never stops processing. */
|
|
71
|
+
createGui?: () => Promise<HTMLElement>;
|
|
72
|
+
/** Releases a GUI element previously built by `createGui` (WAM destroyGui). */
|
|
73
|
+
destroyGui?: (gui: HTMLElement) => void;
|
|
74
|
+
/** Parameter metadata for the generic fallback panel (WAM getParameterInfo). */
|
|
75
|
+
getParameterInfo?: () => Promise<unknown>;
|
|
76
|
+
}
|
|
77
|
+
/** A registered effect type. `create` must work on any BaseAudioContext so
|
|
78
|
+
* the same definitions serve offline rendering. */
|
|
79
|
+
interface EffectDefinition {
|
|
80
|
+
label: string;
|
|
81
|
+
category: string;
|
|
82
|
+
defaults: Record<string, number>;
|
|
83
|
+
params: Record<string, EffectParamDef>;
|
|
84
|
+
/** Name of the wet/dry param, when the effect has one. Bypass zeroes it
|
|
85
|
+
* (storing the original); effects without one are bypassed by
|
|
86
|
+
* disconnection. */
|
|
87
|
+
wetParam?: string;
|
|
88
|
+
create: (audioContext: BaseAudioContext, params: Record<string, number>) => EffectInstance;
|
|
89
|
+
}
|
|
90
|
+
/** Public, serializable view of one chain entry. */
|
|
91
|
+
interface EffectState {
|
|
92
|
+
id: string;
|
|
93
|
+
kind: string;
|
|
94
|
+
type: string;
|
|
95
|
+
params: Record<string, number>;
|
|
96
|
+
bypassed: boolean;
|
|
97
|
+
url?: string;
|
|
98
|
+
/** Present on Faust entries: the DSP source this effect was compiled from. */
|
|
99
|
+
source?: {
|
|
100
|
+
faust: string;
|
|
101
|
+
};
|
|
102
|
+
label?: string;
|
|
103
|
+
error?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Persisted form of a chain — see README for the consumer contract. */
|
|
106
|
+
type SerializedEffectEntry = {
|
|
107
|
+
kind: 'native';
|
|
108
|
+
type: string;
|
|
109
|
+
params: Record<string, number>;
|
|
110
|
+
bypassed: boolean;
|
|
111
|
+
} | {
|
|
112
|
+
kind: 'wam';
|
|
113
|
+
/** Module URL for url-loaded plugins. Absent for Faust entries. */
|
|
114
|
+
url?: string;
|
|
115
|
+
bypassed: boolean;
|
|
116
|
+
state?: unknown;
|
|
117
|
+
/** Faust DSP source — restore recompiles in-browser via @dawcore/faust
|
|
118
|
+
* instead of fetching a URL. */
|
|
119
|
+
faustDsp?: string;
|
|
120
|
+
/** Name the Faust entry was compiled under (restores the same label). */
|
|
121
|
+
faustName?: string;
|
|
122
|
+
};
|
|
123
|
+
/** Result of creating an effect via the registry. */
|
|
124
|
+
interface CreatedEffect {
|
|
125
|
+
instance: EffectInstance;
|
|
126
|
+
params: Record<string, number>;
|
|
127
|
+
wetParam?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
49
130
|
declare class DawTrackElement extends LitElement {
|
|
50
131
|
src: string;
|
|
51
132
|
name: string;
|
|
@@ -59,6 +140,35 @@ declare class DawTrackElement extends LitElement {
|
|
|
59
140
|
spectrogramConfig: SpectrogramConfig | null;
|
|
60
141
|
readonly trackId: `${string}-${string}-${string}-${string}-${string}`;
|
|
61
142
|
createRenderRoot(): this;
|
|
143
|
+
addEffect(type: string, params?: Record<string, number>): string;
|
|
144
|
+
/** Load a WAM plugin (via the optional @dawcore/wam peer) into this track's chain. */
|
|
145
|
+
addWamPlugin(url: string, initialState?: unknown): Promise<string>;
|
|
146
|
+
/**
|
|
147
|
+
* Compile Faust DSP source in the browser (via the optional @dawcore/faust
|
|
148
|
+
* peer) and add the resulting WAM to this track's chain. Compile errors
|
|
149
|
+
* keep their Faust line/column diagnostics and leave the chain untouched.
|
|
150
|
+
*/
|
|
151
|
+
addFaustEffect(dspCode: string, options?: {
|
|
152
|
+
name?: string;
|
|
153
|
+
}): Promise<string>;
|
|
154
|
+
/** Snapshot this track's chain in its persisted form (see dawcore README). */
|
|
155
|
+
getEffectsState(): Promise<SerializedEffectEntry[]>;
|
|
156
|
+
/** Replace this track's chain with a persisted snapshot. */
|
|
157
|
+
setEffectsState(entries: SerializedEffectEntry[]): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Open (lazily creating) the GUI for one of this track's effects into a
|
|
160
|
+
* consumer-provided container. Closing hides without interrupting audio;
|
|
161
|
+
* the element is cached for reopen. See <daw-editor>.openEffectGui.
|
|
162
|
+
*/
|
|
163
|
+
openEffectGui(effectId: string, container: HTMLElement): Promise<HTMLElement>;
|
|
164
|
+
/** Hide an effect's GUI (cached for reopen — never destroys). */
|
|
165
|
+
closeEffectGui(effectId: string): void;
|
|
166
|
+
removeEffect(effectId: string): void;
|
|
167
|
+
setEffectParams(effectId: string, params: Record<string, number>): void;
|
|
168
|
+
setEffectBypassed(effectId: string, bypassed: boolean): void;
|
|
169
|
+
moveEffect(effectId: string, newIndex: number): void;
|
|
170
|
+
get effects(): EffectState[];
|
|
171
|
+
private _effectsEditor;
|
|
62
172
|
connectedCallback(): void;
|
|
63
173
|
private _hasRendered;
|
|
64
174
|
updated(changed: PropertyValues): void;
|
|
@@ -826,6 +936,45 @@ interface DawSpectrogramErrorDetail {
|
|
|
826
936
|
generation: number;
|
|
827
937
|
error: Error;
|
|
828
938
|
}
|
|
939
|
+
interface DawEffectAddDetail {
|
|
940
|
+
effectId: string;
|
|
941
|
+
kind: string;
|
|
942
|
+
type: string;
|
|
943
|
+
params: Record<string, number>;
|
|
944
|
+
index: number;
|
|
945
|
+
/** Plugin source URL (kind 'wam', url-loaded). */
|
|
946
|
+
url?: string;
|
|
947
|
+
/** Faust DSP source (kind 'wam', compiled in-browser via @dawcore/faust). */
|
|
948
|
+
source?: {
|
|
949
|
+
faust: string;
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
interface DawEffectRemoveDetail {
|
|
953
|
+
effectId: string;
|
|
954
|
+
}
|
|
955
|
+
interface DawEffectChangeDetail {
|
|
956
|
+
effectId: string;
|
|
957
|
+
params: Record<string, number>;
|
|
958
|
+
}
|
|
959
|
+
interface DawEffectBypassDetail {
|
|
960
|
+
effectId: string;
|
|
961
|
+
bypassed: boolean;
|
|
962
|
+
}
|
|
963
|
+
interface DawEffectReorderDetail {
|
|
964
|
+
effectId: string;
|
|
965
|
+
fromIndex: number;
|
|
966
|
+
toIndex: number;
|
|
967
|
+
}
|
|
968
|
+
interface DawEffectErrorDetail {
|
|
969
|
+
effectId: string;
|
|
970
|
+
/** Plugin source URL (absent for Faust entries, which have no URL). */
|
|
971
|
+
url?: string;
|
|
972
|
+
/** Faust DSP source of the failed entry, when applicable. */
|
|
973
|
+
source?: {
|
|
974
|
+
faust: string;
|
|
975
|
+
};
|
|
976
|
+
message: string;
|
|
977
|
+
}
|
|
829
978
|
interface DawEventMap {
|
|
830
979
|
'daw-selection': CustomEvent<DawSelectionDetail>;
|
|
831
980
|
'daw-seek': CustomEvent<DawSeekDetail>;
|
|
@@ -855,6 +1004,12 @@ interface DawEventMap {
|
|
|
855
1004
|
'daw-clip-split': CustomEvent<DawClipSplitDetail>;
|
|
856
1005
|
'daw-spectrogram-ready': CustomEvent<DawSpectrogramReadyDetail>;
|
|
857
1006
|
'daw-spectrogram-error': CustomEvent<DawSpectrogramErrorDetail>;
|
|
1007
|
+
'daw-effect-add': CustomEvent<DawEffectAddDetail>;
|
|
1008
|
+
'daw-effect-remove': CustomEvent<DawEffectRemoveDetail>;
|
|
1009
|
+
'daw-effect-change': CustomEvent<DawEffectChangeDetail>;
|
|
1010
|
+
'daw-effect-bypass': CustomEvent<DawEffectBypassDetail>;
|
|
1011
|
+
'daw-effect-reorder': CustomEvent<DawEffectReorderDetail>;
|
|
1012
|
+
'daw-effect-error': CustomEvent<DawEffectErrorDetail>;
|
|
858
1013
|
}
|
|
859
1014
|
type DawEvent<K extends keyof DawEventMap> = DawEventMap[K];
|
|
860
1015
|
interface LoadFilesResult {
|
|
@@ -887,6 +1042,42 @@ interface MidiLoaderHost {
|
|
|
887
1042
|
querySelectorAll(selector: string): NodeListOf<Element>;
|
|
888
1043
|
}
|
|
889
1044
|
|
|
1045
|
+
interface ExportOptions {
|
|
1046
|
+
/** Default: the host's sample rate. */
|
|
1047
|
+
sampleRate?: number;
|
|
1048
|
+
/** Window start in seconds. Default: 0. */
|
|
1049
|
+
startTime?: number;
|
|
1050
|
+
/** Window length in seconds. Default: host duration minus startTime. */
|
|
1051
|
+
duration?: number;
|
|
1052
|
+
/** Default: 2 (stereo). */
|
|
1053
|
+
channels?: 1 | 2;
|
|
1054
|
+
}
|
|
1055
|
+
interface ExportClip {
|
|
1056
|
+
startSample: number;
|
|
1057
|
+
durationSamples: number;
|
|
1058
|
+
offsetSamples: number;
|
|
1059
|
+
sampleRate: number;
|
|
1060
|
+
gain?: number;
|
|
1061
|
+
audioBuffer?: AudioBuffer;
|
|
1062
|
+
}
|
|
1063
|
+
interface ExportTrack {
|
|
1064
|
+
id: string;
|
|
1065
|
+
volume: number;
|
|
1066
|
+
pan: number;
|
|
1067
|
+
muted: boolean;
|
|
1068
|
+
soloed: boolean;
|
|
1069
|
+
clips: ExportClip[];
|
|
1070
|
+
}
|
|
1071
|
+
/** What the editor provides to the export pipeline. */
|
|
1072
|
+
interface ExportAudioHost {
|
|
1073
|
+
effectiveSampleRate: number;
|
|
1074
|
+
/** Natural session duration in seconds. */
|
|
1075
|
+
duration: number;
|
|
1076
|
+
tracks: ExportTrack[];
|
|
1077
|
+
getMasterEffectsState(): Promise<SerializedEffectEntry[]>;
|
|
1078
|
+
getTrackEffectsState(trackId: string): Promise<SerializedEffectEntry[]>;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
890
1081
|
declare class DawEditorElement extends LitElement implements MidiLoaderHost {
|
|
891
1082
|
get samplesPerPixel(): number;
|
|
892
1083
|
set samplesPerPixel(value: number);
|
|
@@ -989,6 +1180,57 @@ declare class DawEditorElement extends LitElement implements MidiLoaderHost {
|
|
|
989
1180
|
set adapter(value: PlayoutAdapter | null);
|
|
990
1181
|
get adapter(): PlayoutAdapter | null;
|
|
991
1182
|
private _externalAdapter;
|
|
1183
|
+
private _effectsManager;
|
|
1184
|
+
private get _effects();
|
|
1185
|
+
/** Master effects chain — inserted between the master bus and the destination. */
|
|
1186
|
+
addEffect(type: string, params?: Record<string, number>): string;
|
|
1187
|
+
removeEffect(effectId: string): void;
|
|
1188
|
+
setEffectParams(effectId: string, params: Record<string, number>): void;
|
|
1189
|
+
setEffectBypassed(effectId: string, bypassed: boolean): void;
|
|
1190
|
+
moveEffect(effectId: string, newIndex: number): void;
|
|
1191
|
+
get effects(): EffectState[];
|
|
1192
|
+
/** Load a WAM plugin (via the optional @dawcore/wam peer) into the master chain. */
|
|
1193
|
+
addWamPlugin(url: string, initialState?: unknown): Promise<string>;
|
|
1194
|
+
/**
|
|
1195
|
+
* Compile Faust DSP source in the browser (via the optional @dawcore/faust
|
|
1196
|
+
* peer) and add the resulting WAM to the master chain. Compile errors keep
|
|
1197
|
+
* their Faust line/column diagnostics and leave the chain untouched.
|
|
1198
|
+
*/
|
|
1199
|
+
addFaustEffect(dspCode: string, options?: {
|
|
1200
|
+
name?: string;
|
|
1201
|
+
}): Promise<string>;
|
|
1202
|
+
/**
|
|
1203
|
+
* Open (lazily creating) the GUI for a master-chain effect into a
|
|
1204
|
+
* consumer-provided container. WAM plugins mount their own GUI; plugins
|
|
1205
|
+
* without one — and native effects — get the generic parameter panel from
|
|
1206
|
+
* @dawcore/wam. The element is cached: closeEffectGui hides it without
|
|
1207
|
+
* interrupting audio, reopening remounts the same element.
|
|
1208
|
+
*/
|
|
1209
|
+
openEffectGui(effectId: string, container: HTMLElement): Promise<HTMLElement>;
|
|
1210
|
+
/** Hide a master-chain effect's GUI (cached for reopen — never destroys). */
|
|
1211
|
+
closeEffectGui(effectId: string): void;
|
|
1212
|
+
/** Snapshot the master chain in its persisted form (see dawcore README). */
|
|
1213
|
+
getEffectsState(): Promise<SerializedEffectEntry[]>;
|
|
1214
|
+
/** Replace the master chain with a persisted snapshot. */
|
|
1215
|
+
setEffectsState(entries: SerializedEffectEntry[]): Promise<void>;
|
|
1216
|
+
/**
|
|
1217
|
+
* Render the session offline through all effect chains (per-track +
|
|
1218
|
+
* master), including WAM plugins (re-instantiated on the offline context
|
|
1219
|
+
* with their live state). Returns the rendered AudioBuffer.
|
|
1220
|
+
*/
|
|
1221
|
+
exportAudio(options?: ExportOptions): Promise<AudioBuffer>;
|
|
1222
|
+
/** Internal — <daw-track> effects API delegates here (dawcore-internal contract). */
|
|
1223
|
+
_trackAddEffect(trackId: string, target: EventTarget, type: string, params?: Record<string, number>): string;
|
|
1224
|
+
_trackEffectOp(trackId: string, target: EventTarget, op: 'remove' | 'setParams' | 'setBypassed' | 'move', effectId: string, arg?: any): void;
|
|
1225
|
+
_trackEffects(trackId: string): EffectState[];
|
|
1226
|
+
_trackAddWamPlugin(trackId: string, target: EventTarget, url: string, initialState?: unknown): Promise<string>;
|
|
1227
|
+
_trackAddFaustEffect(trackId: string, target: EventTarget, dspCode: string, options?: {
|
|
1228
|
+
name?: string;
|
|
1229
|
+
}): Promise<string>;
|
|
1230
|
+
_trackOpenEffectGui(trackId: string, target: EventTarget, effectId: string, container: HTMLElement): Promise<HTMLElement>;
|
|
1231
|
+
_trackCloseEffectGui(_trackId: string, effectId: string): void;
|
|
1232
|
+
_trackGetEffectsState(trackId: string): Promise<SerializedEffectEntry[]>;
|
|
1233
|
+
_trackSetEffectsState(trackId: string, target: EventTarget, entries: SerializedEffectEntry[]): Promise<void>;
|
|
992
1234
|
get audioContext(): AudioContext;
|
|
993
1235
|
_engine: PlaylistEngine | null;
|
|
994
1236
|
private _warnedMissingTicksToSeconds;
|
|
@@ -1496,4 +1738,9 @@ interface SplitHost {
|
|
|
1496
1738
|
*/
|
|
1497
1739
|
declare function splitAtPlayhead(host: SplitHost): boolean;
|
|
1498
1740
|
|
|
1499
|
-
|
|
1741
|
+
declare function registerEffect(type: string, definition: EffectDefinition): void;
|
|
1742
|
+
/** A copy — mutating the returned map does not affect the registry. */
|
|
1743
|
+
declare function getEffectDefinitions(): Map<string, EffectDefinition>;
|
|
1744
|
+
declare function createEffectInstance(type: string, audioContext: BaseAudioContext, params?: Record<string, number>): CreatedEffect;
|
|
1745
|
+
|
|
1746
|
+
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 DawEffectAddDetail, type DawEffectBypassDetail, type DawEffectChangeDetail, type DawEffectErrorDetail, type DawEffectRemoveDetail, type DawEffectReorderDetail, 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 EffectDefinition, type EffectInstance, type EffectParamDef, type EffectState, type ExportAudioHost, type ExportOptions, type KeyBinding, type LoadFilesResult, type PlaybackShortcutMap, type PointerEngineContract, RecordingController, type RecordingOptions, type RecordingSession, type SerializedEffectEntry, SpectrogramController, type SplitEngineContract, type SplitHost, type SplittingShortcutMap, type TrackConfig, type TrackDescriptor, type TrackRenderMode, type UndoShortcutMap, type WaveformSegment, createEffectInstance, getEffectDefinitions, isDomClip, registerEffect, splitAtPlayhead };
|