@dawcore/components 0.0.3 → 0.0.4
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 +29 -4
- package/dist/index.d.ts +29 -4
- package/dist/index.js +181 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +181 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as lit from 'lit';
|
|
2
2
|
import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost } from 'lit';
|
|
3
3
|
import { Peaks, Bits, FadeType, PeakData, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
|
|
4
|
+
import WaveformData from 'waveform-data';
|
|
4
5
|
import { PlaylistEngine } from '@waveform-playlist/engine';
|
|
5
6
|
|
|
6
7
|
declare class DawClipElement extends LitElement {
|
|
@@ -184,6 +185,7 @@ interface TrackDescriptor {
|
|
|
184
185
|
}
|
|
185
186
|
interface ClipDescriptor {
|
|
186
187
|
src: string;
|
|
188
|
+
peaksSrc: string;
|
|
187
189
|
start: number;
|
|
188
190
|
duration: number;
|
|
189
191
|
offset: number;
|
|
@@ -213,6 +215,11 @@ declare class PeakPipeline {
|
|
|
213
215
|
private _baseScale;
|
|
214
216
|
private _bits;
|
|
215
217
|
constructor(baseScale?: number, bits?: 8 | 16);
|
|
218
|
+
/**
|
|
219
|
+
* Inject externally-loaded WaveformData (e.g., from a .dat file) into the cache.
|
|
220
|
+
* Prevents worker generation for this AudioBuffer on all subsequent calls.
|
|
221
|
+
*/
|
|
222
|
+
cacheWaveformData(audioBuffer: AudioBuffer, waveformData: WaveformData): void;
|
|
216
223
|
/**
|
|
217
224
|
* Generate PeakData for a clip from its AudioBuffer.
|
|
218
225
|
* Uses cached WaveformData when available; otherwise generates via worker.
|
|
@@ -221,14 +228,26 @@ declare class PeakPipeline {
|
|
|
221
228
|
generatePeaks(audioBuffer: AudioBuffer, samplesPerPixel: number, isMono: boolean, offsetSamples?: number, durationSamples?: number): Promise<PeakData>;
|
|
222
229
|
/**
|
|
223
230
|
* Re-extract peaks for all clips at a new zoom level using cached WaveformData.
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
231
|
+
* Returns a new Map of clipId → PeakData. Clips without cached data are skipped.
|
|
232
|
+
* When the requested scale is finer than cached data, peaks are clamped to the
|
|
233
|
+
* cached scale and a single summary warning is logged.
|
|
227
234
|
*/
|
|
228
235
|
reextractPeaks(clipBuffers: ReadonlyMap<string, AudioBuffer>, samplesPerPixel: number, isMono: boolean, clipOffsets?: ReadonlyMap<string, {
|
|
229
236
|
offsetSamples: number;
|
|
230
237
|
durationSamples: number;
|
|
231
238
|
}>): Map<string, PeakData>;
|
|
239
|
+
/**
|
|
240
|
+
* Clamp requested scale to cached WaveformData scale.
|
|
241
|
+
* WaveformData.resample() can only go coarser — if the requested zoom is
|
|
242
|
+
* finer than the cached data, use the cached scale. Set warn=true to log
|
|
243
|
+
* (default); reextractPeaks passes false and logs a single summary instead.
|
|
244
|
+
*/
|
|
245
|
+
private _clampScale;
|
|
246
|
+
/**
|
|
247
|
+
* Return the coarsest (largest) scale among cached WaveformData entries
|
|
248
|
+
* that correspond to the given clip buffers. Returns 0 if none are cached.
|
|
249
|
+
*/
|
|
250
|
+
getMaxCachedScale(clipBuffers: ReadonlyMap<string, AudioBuffer>): number;
|
|
232
251
|
terminate(): void;
|
|
233
252
|
private _getWaveformData;
|
|
234
253
|
}
|
|
@@ -516,7 +535,9 @@ interface LoadFilesResult {
|
|
|
516
535
|
}
|
|
517
536
|
|
|
518
537
|
declare class DawEditorElement extends LitElement {
|
|
519
|
-
samplesPerPixel: number;
|
|
538
|
+
get samplesPerPixel(): number;
|
|
539
|
+
set samplesPerPixel(value: number);
|
|
540
|
+
private _samplesPerPixel;
|
|
520
541
|
waveHeight: number;
|
|
521
542
|
timescale: boolean;
|
|
522
543
|
mono: boolean;
|
|
@@ -543,12 +564,15 @@ declare class DawEditorElement extends LitElement {
|
|
|
543
564
|
_engine: PlaylistEngine | null;
|
|
544
565
|
private _enginePromise;
|
|
545
566
|
_audioCache: Map<string, Promise<AudioBuffer>>;
|
|
567
|
+
private _peaksCache;
|
|
546
568
|
_clipBuffers: Map<string, AudioBuffer>;
|
|
547
569
|
_clipOffsets: Map<string, {
|
|
548
570
|
offsetSamples: number;
|
|
549
571
|
durationSamples: number;
|
|
550
572
|
}>;
|
|
551
573
|
_peakPipeline: PeakPipeline;
|
|
574
|
+
/** Coarsest scale from pre-computed peaks — zoom cannot go finer than this. 0 = no limit. */
|
|
575
|
+
private _minSamplesPerPixel;
|
|
552
576
|
private _trackElements;
|
|
553
577
|
private _childObserver;
|
|
554
578
|
private _audioResume;
|
|
@@ -588,6 +612,7 @@ declare class DawEditorElement extends LitElement {
|
|
|
588
612
|
private _readTrackDescriptor;
|
|
589
613
|
private _loadTrack;
|
|
590
614
|
_fetchAndDecode(src: string): Promise<AudioBuffer>;
|
|
615
|
+
private _fetchPeaks;
|
|
591
616
|
_recomputeDuration(): void;
|
|
592
617
|
_ensureEngine(): Promise<PlaylistEngine>;
|
|
593
618
|
private _buildEngine;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as lit from 'lit';
|
|
2
2
|
import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost } from 'lit';
|
|
3
3
|
import { Peaks, Bits, FadeType, PeakData, ClipTrack, KeyboardShortcut } from '@waveform-playlist/core';
|
|
4
|
+
import WaveformData from 'waveform-data';
|
|
4
5
|
import { PlaylistEngine } from '@waveform-playlist/engine';
|
|
5
6
|
|
|
6
7
|
declare class DawClipElement extends LitElement {
|
|
@@ -184,6 +185,7 @@ interface TrackDescriptor {
|
|
|
184
185
|
}
|
|
185
186
|
interface ClipDescriptor {
|
|
186
187
|
src: string;
|
|
188
|
+
peaksSrc: string;
|
|
187
189
|
start: number;
|
|
188
190
|
duration: number;
|
|
189
191
|
offset: number;
|
|
@@ -213,6 +215,11 @@ declare class PeakPipeline {
|
|
|
213
215
|
private _baseScale;
|
|
214
216
|
private _bits;
|
|
215
217
|
constructor(baseScale?: number, bits?: 8 | 16);
|
|
218
|
+
/**
|
|
219
|
+
* Inject externally-loaded WaveformData (e.g., from a .dat file) into the cache.
|
|
220
|
+
* Prevents worker generation for this AudioBuffer on all subsequent calls.
|
|
221
|
+
*/
|
|
222
|
+
cacheWaveformData(audioBuffer: AudioBuffer, waveformData: WaveformData): void;
|
|
216
223
|
/**
|
|
217
224
|
* Generate PeakData for a clip from its AudioBuffer.
|
|
218
225
|
* Uses cached WaveformData when available; otherwise generates via worker.
|
|
@@ -221,14 +228,26 @@ declare class PeakPipeline {
|
|
|
221
228
|
generatePeaks(audioBuffer: AudioBuffer, samplesPerPixel: number, isMono: boolean, offsetSamples?: number, durationSamples?: number): Promise<PeakData>;
|
|
222
229
|
/**
|
|
223
230
|
* Re-extract peaks for all clips at a new zoom level using cached WaveformData.
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
231
|
+
* Returns a new Map of clipId → PeakData. Clips without cached data are skipped.
|
|
232
|
+
* When the requested scale is finer than cached data, peaks are clamped to the
|
|
233
|
+
* cached scale and a single summary warning is logged.
|
|
227
234
|
*/
|
|
228
235
|
reextractPeaks(clipBuffers: ReadonlyMap<string, AudioBuffer>, samplesPerPixel: number, isMono: boolean, clipOffsets?: ReadonlyMap<string, {
|
|
229
236
|
offsetSamples: number;
|
|
230
237
|
durationSamples: number;
|
|
231
238
|
}>): Map<string, PeakData>;
|
|
239
|
+
/**
|
|
240
|
+
* Clamp requested scale to cached WaveformData scale.
|
|
241
|
+
* WaveformData.resample() can only go coarser — if the requested zoom is
|
|
242
|
+
* finer than the cached data, use the cached scale. Set warn=true to log
|
|
243
|
+
* (default); reextractPeaks passes false and logs a single summary instead.
|
|
244
|
+
*/
|
|
245
|
+
private _clampScale;
|
|
246
|
+
/**
|
|
247
|
+
* Return the coarsest (largest) scale among cached WaveformData entries
|
|
248
|
+
* that correspond to the given clip buffers. Returns 0 if none are cached.
|
|
249
|
+
*/
|
|
250
|
+
getMaxCachedScale(clipBuffers: ReadonlyMap<string, AudioBuffer>): number;
|
|
232
251
|
terminate(): void;
|
|
233
252
|
private _getWaveformData;
|
|
234
253
|
}
|
|
@@ -516,7 +535,9 @@ interface LoadFilesResult {
|
|
|
516
535
|
}
|
|
517
536
|
|
|
518
537
|
declare class DawEditorElement extends LitElement {
|
|
519
|
-
samplesPerPixel: number;
|
|
538
|
+
get samplesPerPixel(): number;
|
|
539
|
+
set samplesPerPixel(value: number);
|
|
540
|
+
private _samplesPerPixel;
|
|
520
541
|
waveHeight: number;
|
|
521
542
|
timescale: boolean;
|
|
522
543
|
mono: boolean;
|
|
@@ -543,12 +564,15 @@ declare class DawEditorElement extends LitElement {
|
|
|
543
564
|
_engine: PlaylistEngine | null;
|
|
544
565
|
private _enginePromise;
|
|
545
566
|
_audioCache: Map<string, Promise<AudioBuffer>>;
|
|
567
|
+
private _peaksCache;
|
|
546
568
|
_clipBuffers: Map<string, AudioBuffer>;
|
|
547
569
|
_clipOffsets: Map<string, {
|
|
548
570
|
offsetSamples: number;
|
|
549
571
|
durationSamples: number;
|
|
550
572
|
}>;
|
|
551
573
|
_peakPipeline: PeakPipeline;
|
|
574
|
+
/** Coarsest scale from pre-computed peaks — zoom cannot go finer than this. 0 = no limit. */
|
|
575
|
+
private _minSamplesPerPixel;
|
|
552
576
|
private _trackElements;
|
|
553
577
|
private _childObserver;
|
|
554
578
|
private _audioResume;
|
|
@@ -588,6 +612,7 @@ declare class DawEditorElement extends LitElement {
|
|
|
588
612
|
private _readTrackDescriptor;
|
|
589
613
|
private _loadTrack;
|
|
590
614
|
_fetchAndDecode(src: string): Promise<AudioBuffer>;
|
|
615
|
+
private _fetchPeaks;
|
|
591
616
|
_recomputeDuration(): void;
|
|
592
617
|
_ensureEngine(): Promise<PlaylistEngine>;
|
|
593
618
|
private _buildEngine;
|
package/dist/index.js
CHANGED
|
@@ -1134,6 +1134,13 @@ var PeakPipeline = class {
|
|
|
1134
1134
|
this._baseScale = baseScale;
|
|
1135
1135
|
this._bits = bits;
|
|
1136
1136
|
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Inject externally-loaded WaveformData (e.g., from a .dat file) into the cache.
|
|
1139
|
+
* Prevents worker generation for this AudioBuffer on all subsequent calls.
|
|
1140
|
+
*/
|
|
1141
|
+
cacheWaveformData(audioBuffer, waveformData) {
|
|
1142
|
+
this._cache.set(audioBuffer, waveformData);
|
|
1143
|
+
}
|
|
1137
1144
|
/**
|
|
1138
1145
|
* Generate PeakData for a clip from its AudioBuffer.
|
|
1139
1146
|
* Uses cached WaveformData when available; otherwise generates via worker.
|
|
@@ -1141,8 +1148,9 @@ var PeakPipeline = class {
|
|
|
1141
1148
|
*/
|
|
1142
1149
|
async generatePeaks(audioBuffer, samplesPerPixel, isMono, offsetSamples, durationSamples) {
|
|
1143
1150
|
const waveformData = await this._getWaveformData(audioBuffer);
|
|
1151
|
+
const effectiveScale = this._clampScale(waveformData, samplesPerPixel);
|
|
1144
1152
|
try {
|
|
1145
|
-
return extractPeaks(waveformData,
|
|
1153
|
+
return extractPeaks(waveformData, effectiveScale, isMono, offsetSamples, durationSamples);
|
|
1146
1154
|
} catch (err) {
|
|
1147
1155
|
console.warn("[dawcore] extractPeaks failed: " + String(err));
|
|
1148
1156
|
throw err;
|
|
@@ -1150,23 +1158,29 @@ var PeakPipeline = class {
|
|
|
1150
1158
|
}
|
|
1151
1159
|
/**
|
|
1152
1160
|
* Re-extract peaks for all clips at a new zoom level using cached WaveformData.
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1161
|
+
* Returns a new Map of clipId → PeakData. Clips without cached data are skipped.
|
|
1162
|
+
* When the requested scale is finer than cached data, peaks are clamped to the
|
|
1163
|
+
* cached scale and a single summary warning is logged.
|
|
1156
1164
|
*/
|
|
1157
1165
|
reextractPeaks(clipBuffers, samplesPerPixel, isMono, clipOffsets) {
|
|
1158
1166
|
const result = /* @__PURE__ */ new Map();
|
|
1167
|
+
let clampedCount = 0;
|
|
1168
|
+
let clampedScale = 0;
|
|
1159
1169
|
for (const [clipId, audioBuffer] of clipBuffers) {
|
|
1160
1170
|
const cached = this._cache.get(audioBuffer);
|
|
1161
1171
|
if (cached) {
|
|
1162
|
-
|
|
1172
|
+
const effectiveScale = this._clampScale(cached, samplesPerPixel, false);
|
|
1173
|
+
if (effectiveScale !== samplesPerPixel) {
|
|
1174
|
+
clampedCount++;
|
|
1175
|
+
clampedScale = effectiveScale;
|
|
1176
|
+
}
|
|
1163
1177
|
try {
|
|
1164
1178
|
const offsets = clipOffsets?.get(clipId);
|
|
1165
1179
|
result.set(
|
|
1166
1180
|
clipId,
|
|
1167
1181
|
extractPeaks(
|
|
1168
1182
|
cached,
|
|
1169
|
-
|
|
1183
|
+
effectiveScale,
|
|
1170
1184
|
isMono,
|
|
1171
1185
|
offsets?.offsetSamples,
|
|
1172
1186
|
offsets?.durationSamples
|
|
@@ -1177,8 +1191,42 @@ var PeakPipeline = class {
|
|
|
1177
1191
|
}
|
|
1178
1192
|
}
|
|
1179
1193
|
}
|
|
1194
|
+
if (clampedCount > 0) {
|
|
1195
|
+
console.warn(
|
|
1196
|
+
"[dawcore] Requested zoom " + samplesPerPixel + " spp is finer than pre-computed peaks (" + clampedScale + " spp) \u2014 " + clampedCount + " clip(s) using available resolution"
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1180
1199
|
return result;
|
|
1181
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Clamp requested scale to cached WaveformData scale.
|
|
1203
|
+
* WaveformData.resample() can only go coarser — if the requested zoom is
|
|
1204
|
+
* finer than the cached data, use the cached scale. Set warn=true to log
|
|
1205
|
+
* (default); reextractPeaks passes false and logs a single summary instead.
|
|
1206
|
+
*/
|
|
1207
|
+
_clampScale(waveformData, requestedScale, warn = true) {
|
|
1208
|
+
if (requestedScale < waveformData.scale) {
|
|
1209
|
+
if (warn) {
|
|
1210
|
+
console.warn(
|
|
1211
|
+
"[dawcore] Requested zoom " + requestedScale + " spp is finer than pre-computed peaks (" + waveformData.scale + " spp) \u2014 using available resolution"
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
return waveformData.scale;
|
|
1215
|
+
}
|
|
1216
|
+
return requestedScale;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Return the coarsest (largest) scale among cached WaveformData entries
|
|
1220
|
+
* that correspond to the given clip buffers. Returns 0 if none are cached.
|
|
1221
|
+
*/
|
|
1222
|
+
getMaxCachedScale(clipBuffers) {
|
|
1223
|
+
let max = 0;
|
|
1224
|
+
for (const audioBuffer of clipBuffers.values()) {
|
|
1225
|
+
const cached = this._cache.get(audioBuffer);
|
|
1226
|
+
if (cached && cached.scale > max) max = cached.scale;
|
|
1227
|
+
}
|
|
1228
|
+
return max;
|
|
1229
|
+
}
|
|
1182
1230
|
terminate() {
|
|
1183
1231
|
this._worker?.terminate();
|
|
1184
1232
|
this._worker = null;
|
|
@@ -2487,6 +2535,7 @@ async function loadFiles(host, files) {
|
|
|
2487
2535
|
clips: [
|
|
2488
2536
|
{
|
|
2489
2537
|
src: "",
|
|
2538
|
+
peaksSrc: "",
|
|
2490
2539
|
start: 0,
|
|
2491
2540
|
duration: audioBuffer.duration,
|
|
2492
2541
|
offset: 0,
|
|
@@ -2572,6 +2621,7 @@ function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamp
|
|
|
2572
2621
|
const sr = host.effectiveSampleRate;
|
|
2573
2622
|
const clipDesc = {
|
|
2574
2623
|
src: "",
|
|
2624
|
+
peaksSrc: "",
|
|
2575
2625
|
start: startSample / sr,
|
|
2576
2626
|
duration: durSamples / sr,
|
|
2577
2627
|
offset: 0,
|
|
@@ -2773,11 +2823,29 @@ function findAudioBufferForClip(host, clip, track) {
|
|
|
2773
2823
|
return null;
|
|
2774
2824
|
}
|
|
2775
2825
|
|
|
2826
|
+
// src/interactions/peaks-loader.ts
|
|
2827
|
+
var import_waveform_data2 = __toESM(require("waveform-data"));
|
|
2828
|
+
async function loadWaveformDataFromUrl(src) {
|
|
2829
|
+
const response = await fetch(src);
|
|
2830
|
+
if (!response.ok) {
|
|
2831
|
+
throw new Error("[dawcore] Failed to fetch peaks data: " + response.statusText);
|
|
2832
|
+
}
|
|
2833
|
+
const { pathname } = new URL(src, globalThis.location?.href ?? "http://localhost");
|
|
2834
|
+
const isBinary = pathname.toLowerCase().endsWith(".dat");
|
|
2835
|
+
if (isBinary) {
|
|
2836
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
2837
|
+
return import_waveform_data2.default.create(arrayBuffer);
|
|
2838
|
+
} else {
|
|
2839
|
+
const json = await response.json();
|
|
2840
|
+
return import_waveform_data2.default.create(json);
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2776
2844
|
// src/elements/daw-editor.ts
|
|
2777
2845
|
var DawEditorElement = class extends import_lit12.LitElement {
|
|
2778
2846
|
constructor() {
|
|
2779
2847
|
super(...arguments);
|
|
2780
|
-
this.
|
|
2848
|
+
this._samplesPerPixel = 1024;
|
|
2781
2849
|
this.waveHeight = 128;
|
|
2782
2850
|
this.timescale = false;
|
|
2783
2851
|
this.mono = false;
|
|
@@ -2804,9 +2872,12 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
2804
2872
|
this._engine = null;
|
|
2805
2873
|
this._enginePromise = null;
|
|
2806
2874
|
this._audioCache = /* @__PURE__ */ new Map();
|
|
2875
|
+
this._peaksCache = /* @__PURE__ */ new Map();
|
|
2807
2876
|
this._clipBuffers = /* @__PURE__ */ new Map();
|
|
2808
2877
|
this._clipOffsets = /* @__PURE__ */ new Map();
|
|
2809
2878
|
this._peakPipeline = new PeakPipeline();
|
|
2879
|
+
/** Coarsest scale from pre-computed peaks — zoom cannot go finer than this. 0 = no limit. */
|
|
2880
|
+
this._minSamplesPerPixel = 0;
|
|
2810
2881
|
this._trackElements = /* @__PURE__ */ new Map();
|
|
2811
2882
|
this._childObserver = null;
|
|
2812
2883
|
this._audioResume = new AudioResumeController(this);
|
|
@@ -2928,6 +2999,21 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
2928
2999
|
// --- Recording ---
|
|
2929
3000
|
this.recordingStream = null;
|
|
2930
3001
|
}
|
|
3002
|
+
get samplesPerPixel() {
|
|
3003
|
+
return this._samplesPerPixel;
|
|
3004
|
+
}
|
|
3005
|
+
set samplesPerPixel(value) {
|
|
3006
|
+
const old = this._samplesPerPixel;
|
|
3007
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
3008
|
+
const clamped = this._minSamplesPerPixel > 0 && value < this._minSamplesPerPixel ? this._minSamplesPerPixel : value;
|
|
3009
|
+
if (clamped !== value) {
|
|
3010
|
+
console.warn(
|
|
3011
|
+
"[dawcore] Zoom " + value + " spp rejected \u2014 pre-computed peaks limit is " + this._minSamplesPerPixel + " spp"
|
|
3012
|
+
);
|
|
3013
|
+
}
|
|
3014
|
+
this._samplesPerPixel = clamped;
|
|
3015
|
+
this.requestUpdate("samplesPerPixel", old);
|
|
3016
|
+
}
|
|
2931
3017
|
get _clipHandler() {
|
|
2932
3018
|
return this.interactiveClips ? this._clipPointer : null;
|
|
2933
3019
|
}
|
|
@@ -3023,9 +3109,11 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3023
3109
|
this._childObserver = null;
|
|
3024
3110
|
this._trackElements.clear();
|
|
3025
3111
|
this._audioCache.clear();
|
|
3112
|
+
this._peaksCache.clear();
|
|
3026
3113
|
this._clipBuffers.clear();
|
|
3027
3114
|
this._clipOffsets.clear();
|
|
3028
3115
|
this._peakPipeline.terminate();
|
|
3116
|
+
this._minSamplesPerPixel = 0;
|
|
3029
3117
|
try {
|
|
3030
3118
|
this._disposeEngine();
|
|
3031
3119
|
} catch (err) {
|
|
@@ -3075,6 +3163,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3075
3163
|
if (this._engine) {
|
|
3076
3164
|
this._engine.removeTrack(trackId);
|
|
3077
3165
|
}
|
|
3166
|
+
this._minSamplesPerPixel = this._peakPipeline.getMaxCachedScale(this._clipBuffers);
|
|
3078
3167
|
if (nextEngine.size === 0) {
|
|
3079
3168
|
this._currentTime = 0;
|
|
3080
3169
|
this._stopPlayhead();
|
|
@@ -3086,6 +3175,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3086
3175
|
if (clipEls.length === 0 && trackEl.src) {
|
|
3087
3176
|
clips.push({
|
|
3088
3177
|
src: trackEl.src,
|
|
3178
|
+
peaksSrc: "",
|
|
3089
3179
|
start: 0,
|
|
3090
3180
|
duration: 0,
|
|
3091
3181
|
offset: 0,
|
|
@@ -3099,6 +3189,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3099
3189
|
for (const clipEl of clipEls) {
|
|
3100
3190
|
clips.push({
|
|
3101
3191
|
src: clipEl.src,
|
|
3192
|
+
peaksSrc: clipEl.peaksSrc,
|
|
3102
3193
|
start: clipEl.start,
|
|
3103
3194
|
duration: clipEl.duration,
|
|
3104
3195
|
offset: clipEl.offset,
|
|
@@ -3126,7 +3217,77 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3126
3217
|
const clips = [];
|
|
3127
3218
|
for (const clipDesc of descriptor.clips) {
|
|
3128
3219
|
if (!clipDesc.src) continue;
|
|
3129
|
-
const
|
|
3220
|
+
const waveformDataPromise = clipDesc.peaksSrc ? this._fetchPeaks(clipDesc.peaksSrc) : null;
|
|
3221
|
+
const audioPromise = this._fetchAndDecode(clipDesc.src);
|
|
3222
|
+
let waveformData = null;
|
|
3223
|
+
if (waveformDataPromise) {
|
|
3224
|
+
try {
|
|
3225
|
+
waveformData = await waveformDataPromise;
|
|
3226
|
+
} catch (err) {
|
|
3227
|
+
console.warn(
|
|
3228
|
+
"[dawcore] Failed to load peaks from " + clipDesc.peaksSrc + ": " + String(err) + " \u2014 falling back to AudioBuffer generation"
|
|
3229
|
+
);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
if (waveformData) {
|
|
3233
|
+
const clip2 = (0, import_core4.createClipFromSeconds)({
|
|
3234
|
+
waveformData,
|
|
3235
|
+
startTime: clipDesc.start,
|
|
3236
|
+
duration: clipDesc.duration || waveformData.duration,
|
|
3237
|
+
offset: clipDesc.offset,
|
|
3238
|
+
gain: clipDesc.gain,
|
|
3239
|
+
name: clipDesc.name,
|
|
3240
|
+
sampleRate: waveformData.sample_rate,
|
|
3241
|
+
sourceDuration: waveformData.duration
|
|
3242
|
+
});
|
|
3243
|
+
const effectiveScale = Math.max(this.samplesPerPixel, waveformData.scale);
|
|
3244
|
+
const peakData2 = extractPeaks(
|
|
3245
|
+
waveformData,
|
|
3246
|
+
effectiveScale,
|
|
3247
|
+
this.mono,
|
|
3248
|
+
clip2.offsetSamples,
|
|
3249
|
+
clip2.durationSamples
|
|
3250
|
+
);
|
|
3251
|
+
this._clipOffsets.set(clip2.id, {
|
|
3252
|
+
offsetSamples: clip2.offsetSamples,
|
|
3253
|
+
durationSamples: clip2.durationSamples
|
|
3254
|
+
});
|
|
3255
|
+
this._peaksData = new Map(this._peaksData).set(clip2.id, peakData2);
|
|
3256
|
+
this._minSamplesPerPixel = Math.max(this._minSamplesPerPixel, waveformData.scale);
|
|
3257
|
+
const previewTrack = (0, import_core4.createTrack)({
|
|
3258
|
+
name: descriptor.name,
|
|
3259
|
+
clips: [clip2],
|
|
3260
|
+
volume: descriptor.volume,
|
|
3261
|
+
pan: descriptor.pan,
|
|
3262
|
+
muted: descriptor.muted,
|
|
3263
|
+
soloed: descriptor.soloed
|
|
3264
|
+
});
|
|
3265
|
+
previewTrack.id = trackId;
|
|
3266
|
+
this._engineTracks = new Map(this._engineTracks).set(trackId, previewTrack);
|
|
3267
|
+
this._recomputeDuration();
|
|
3268
|
+
let audioBuffer2;
|
|
3269
|
+
try {
|
|
3270
|
+
audioBuffer2 = await audioPromise;
|
|
3271
|
+
} catch (audioErr) {
|
|
3272
|
+
const nextPeaks = new Map(this._peaksData);
|
|
3273
|
+
nextPeaks.delete(clip2.id);
|
|
3274
|
+
this._peaksData = nextPeaks;
|
|
3275
|
+
this._clipOffsets.delete(clip2.id);
|
|
3276
|
+
const nextEngine = new Map(this._engineTracks);
|
|
3277
|
+
nextEngine.delete(trackId);
|
|
3278
|
+
this._engineTracks = nextEngine;
|
|
3279
|
+
this._minSamplesPerPixel = this._peakPipeline.getMaxCachedScale(this._clipBuffers);
|
|
3280
|
+
this._recomputeDuration();
|
|
3281
|
+
throw audioErr;
|
|
3282
|
+
}
|
|
3283
|
+
this._resolvedSampleRate = audioBuffer2.sampleRate;
|
|
3284
|
+
const updatedClip = { ...clip2, audioBuffer: audioBuffer2 };
|
|
3285
|
+
this._clipBuffers = new Map(this._clipBuffers).set(clip2.id, audioBuffer2);
|
|
3286
|
+
this._peakPipeline.cacheWaveformData(audioBuffer2, waveformData);
|
|
3287
|
+
clips.push(updatedClip);
|
|
3288
|
+
continue;
|
|
3289
|
+
}
|
|
3290
|
+
const audioBuffer = await audioPromise;
|
|
3130
3291
|
this._resolvedSampleRate = audioBuffer.sampleRate;
|
|
3131
3292
|
const clip = (0, import_core4.createClipFromSeconds)({
|
|
3132
3293
|
audioBuffer,
|
|
@@ -3208,6 +3369,16 @@ var DawEditorElement = class extends import_lit12.LitElement {
|
|
|
3208
3369
|
throw err;
|
|
3209
3370
|
}
|
|
3210
3371
|
}
|
|
3372
|
+
_fetchPeaks(src) {
|
|
3373
|
+
const cached = this._peaksCache.get(src);
|
|
3374
|
+
if (cached) return cached;
|
|
3375
|
+
const promise = loadWaveformDataFromUrl(src).catch((err) => {
|
|
3376
|
+
this._peaksCache.delete(src);
|
|
3377
|
+
throw err;
|
|
3378
|
+
});
|
|
3379
|
+
this._peaksCache.set(src, promise);
|
|
3380
|
+
return promise;
|
|
3381
|
+
}
|
|
3211
3382
|
_recomputeDuration() {
|
|
3212
3383
|
let maxSample = 0;
|
|
3213
3384
|
for (const track of this._engineTracks.values()) {
|
|
@@ -3620,8 +3791,8 @@ DawEditorElement.styles = [
|
|
|
3620
3791
|
];
|
|
3621
3792
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
3622
3793
|
__decorateClass([
|
|
3623
|
-
(0, import_decorators10.property)({ type: Number, attribute: "samples-per-pixel" })
|
|
3624
|
-
], DawEditorElement.prototype, "samplesPerPixel",
|
|
3794
|
+
(0, import_decorators10.property)({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
3795
|
+
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
3625
3796
|
__decorateClass([
|
|
3626
3797
|
(0, import_decorators10.property)({ type: Number, attribute: "wave-height" })
|
|
3627
3798
|
], DawEditorElement.prototype, "waveHeight", 2);
|