@dawcore/components 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -547,7 +547,8 @@ declare class DawEditorElement extends LitElement {
547
547
  clipHeaders: boolean;
548
548
  clipHeaderHeight: number;
549
549
  interactiveClips: boolean;
550
- /** Initial sample rate hint. Overridden by decoded audio buffer's actual rate. */
550
+ /** Desired sample rate. Creates a cross-browser AudioContext at this rate.
551
+ * Pre-computed .dat peaks render instantly when they match. */
551
552
  sampleRate: number;
552
553
  /** Resolved sample rate — falls back to sampleRate property until first audio decode. */
553
554
  _resolvedSampleRate: number | null;
@@ -611,6 +612,13 @@ declare class DawEditorElement extends LitElement {
611
612
  private _onTrackRemoveRequest;
612
613
  private _readTrackDescriptor;
613
614
  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;
614
622
  _fetchAndDecode(src: string): Promise<AudioBuffer>;
615
623
  private _fetchPeaks;
616
624
  _recomputeDuration(): void;
package/dist/index.d.ts CHANGED
@@ -547,7 +547,8 @@ declare class DawEditorElement extends LitElement {
547
547
  clipHeaders: boolean;
548
548
  clipHeaderHeight: number;
549
549
  interactiveClips: boolean;
550
- /** Initial sample rate hint. Overridden by decoded audio buffer's actual rate. */
550
+ /** Desired sample rate. Creates a cross-browser AudioContext at this rate.
551
+ * Pre-computed .dat peaks render instantly when they match. */
551
552
  sampleRate: number;
552
553
  /** Resolved sample rate — falls back to sampleRate property until first audio decode. */
553
554
  _resolvedSampleRate: number | null;
@@ -611,6 +612,13 @@ declare class DawEditorElement extends LitElement {
611
612
  private _onTrackRemoveRequest;
612
613
  private _readTrackDescriptor;
613
614
  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;
614
622
  _fetchAndDecode(src: string): Promise<AudioBuffer>;
615
623
  private _fetchPeaks;
616
624
  _recomputeDuration(): void;
package/dist/index.js CHANGED
@@ -2963,6 +2963,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
2963
2963
  this._onTrackRemoved(trackId);
2964
2964
  }
2965
2965
  };
2966
+ this._contextConfigurePromise = null;
2966
2967
  // --- File Drop ---
2967
2968
  this._onDragOver = (e) => {
2968
2969
  if (!this.fileDrop) return;
@@ -3114,6 +3115,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
3114
3115
  this._clipOffsets.clear();
3115
3116
  this._peakPipeline.terminate();
3116
3117
  this._minSamplesPerPixel = 0;
3118
+ this._contextConfigurePromise = null;
3117
3119
  try {
3118
3120
  this._disposeEngine();
3119
3121
  } catch (err) {
@@ -3222,7 +3224,17 @@ var DawEditorElement = class extends import_lit12.LitElement {
3222
3224
  let waveformData = null;
3223
3225
  if (waveformDataPromise) {
3224
3226
  try {
3225
- waveformData = await waveformDataPromise;
3227
+ const wd = await waveformDataPromise;
3228
+ await this._ensureContextConfigured();
3229
+ const { getGlobalAudioContext } = await import("@waveform-playlist/playout");
3230
+ const contextRate = getGlobalAudioContext().sampleRate;
3231
+ if (wd.sample_rate === contextRate) {
3232
+ waveformData = wd;
3233
+ } else {
3234
+ console.warn(
3235
+ "[dawcore] Pre-computed peaks at " + wd.sample_rate + " Hz do not match AudioContext at " + contextRate + " Hz \u2014 ignoring " + clipDesc.peaksSrc + ", generating from audio"
3236
+ );
3237
+ }
3226
3238
  } catch (err) {
3227
3239
  console.warn(
3228
3240
  "[dawcore] Failed to load peaks from " + clipDesc.peaksSrc + ": " + String(err) + " \u2014 falling back to AudioBuffer generation"
@@ -3230,15 +3242,16 @@ var DawEditorElement = class extends import_lit12.LitElement {
3230
3242
  }
3231
3243
  }
3232
3244
  if (waveformData) {
3233
- const clip2 = (0, import_core4.createClipFromSeconds)({
3245
+ const wdRate = waveformData.sample_rate;
3246
+ const clip2 = (0, import_core4.createClip)({
3234
3247
  waveformData,
3235
- startTime: clipDesc.start,
3236
- duration: clipDesc.duration || waveformData.duration,
3237
- offset: clipDesc.offset,
3248
+ startSample: Math.round(clipDesc.start * wdRate),
3249
+ durationSamples: Math.round((clipDesc.duration || waveformData.duration) * wdRate),
3250
+ offsetSamples: Math.round(clipDesc.offset * wdRate),
3238
3251
  gain: clipDesc.gain,
3239
3252
  name: clipDesc.name,
3240
- sampleRate: waveformData.sample_rate,
3241
- sourceDuration: waveformData.duration
3253
+ sampleRate: wdRate,
3254
+ sourceDurationSamples: Math.ceil(waveformData.duration * wdRate)
3242
3255
  });
3243
3256
  const effectiveScale = Math.max(this.samplesPerPixel, waveformData.scale);
3244
3257
  const peakData2 = extractPeaks(
@@ -3346,6 +3359,30 @@ var DawEditorElement = class extends import_lit12.LitElement {
3346
3359
  );
3347
3360
  }
3348
3361
  }
3362
+ /**
3363
+ * Ensure the global AudioContext is configured with the editor's sample-rate hint
3364
+ * before the first audio operation. Idempotent — concurrent callers await the
3365
+ * same promise so no one proceeds to getGlobalAudioContext() before configuration.
3366
+ */
3367
+ _ensureContextConfigured() {
3368
+ if (!this._contextConfigurePromise) {
3369
+ this._contextConfigurePromise = (async () => {
3370
+ const { configureGlobalContext } = await import("@waveform-playlist/playout");
3371
+ const actualRate = configureGlobalContext({
3372
+ sampleRate: this.sampleRate
3373
+ });
3374
+ if (actualRate !== this.sampleRate) {
3375
+ console.warn(
3376
+ "[dawcore] Requested sampleRate " + this.sampleRate + " but AudioContext is running at " + actualRate
3377
+ );
3378
+ }
3379
+ })().catch((err) => {
3380
+ this._contextConfigurePromise = null;
3381
+ throw err;
3382
+ });
3383
+ }
3384
+ return this._contextConfigurePromise;
3385
+ }
3349
3386
  async _fetchAndDecode(src) {
3350
3387
  if (this._audioCache.has(src)) {
3351
3388
  return this._audioCache.get(src);
@@ -3358,6 +3395,7 @@ var DawEditorElement = class extends import_lit12.LitElement {
3358
3395
  );
3359
3396
  }
3360
3397
  const arrayBuffer = await response.arrayBuffer();
3398
+ await this._ensureContextConfigured();
3361
3399
  const { getGlobalAudioContext } = await import("@waveform-playlist/playout");
3362
3400
  return getGlobalAudioContext().decodeAudioData(arrayBuffer);
3363
3401
  })();