@dawcore/components 0.0.9 → 0.0.10
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 +17 -19
- package/dist/index.d.mts +129 -3
- package/dist/index.d.ts +129 -3
- package/dist/index.js +816 -182
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +799 -166
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -14
package/dist/index.mjs
CHANGED
|
@@ -193,7 +193,7 @@ function getVisibleChunkIndices(totalWidth, chunkWidth, visibleStart, visibleEnd
|
|
|
193
193
|
|
|
194
194
|
// src/elements/daw-waveform.ts
|
|
195
195
|
var MAX_CANVAS_WIDTH = 1e3;
|
|
196
|
-
var LAYOUT_PROPS = /* @__PURE__ */ new Set(["length", "waveHeight", "barWidth", "barGap"]);
|
|
196
|
+
var LAYOUT_PROPS = /* @__PURE__ */ new Set(["length", "waveHeight", "barWidth", "barGap", "segments"]);
|
|
197
197
|
function groupDirtyByChunk(dirtyPixels, step) {
|
|
198
198
|
const dirtyByChunk = /* @__PURE__ */ new Map();
|
|
199
199
|
for (const peakIdx of dirtyPixels) {
|
|
@@ -300,14 +300,22 @@ var DawWaveformElement = class extends LitElement3 {
|
|
|
300
300
|
const halfHeight = this.waveHeight / 2;
|
|
301
301
|
const bits = this.bits;
|
|
302
302
|
const waveColor = getComputedStyle(this).getPropertyValue("--daw-wave-color").trim() || "#c49a6c";
|
|
303
|
-
const dirtyByChunk = groupDirtyByChunk(this._dirtyPixels, step);
|
|
304
303
|
this._drawnChunks.clear();
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
304
|
+
if (this.segments) {
|
|
305
|
+
for (const canvas of canvases) {
|
|
306
|
+
const chunkIdx = Number(canvas.dataset.index);
|
|
307
|
+
this._drawnChunks.add(chunkIdx);
|
|
308
|
+
this._drawSegments(canvas, chunkIdx, dpr, halfHeight, bits, waveColor);
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
const dirtyByChunk = groupDirtyByChunk(this._dirtyPixels, step);
|
|
312
|
+
for (const canvas of canvases) {
|
|
313
|
+
const chunkIdx = Number(canvas.dataset.index);
|
|
314
|
+
this._drawnChunks.add(chunkIdx);
|
|
315
|
+
const range = dirtyByChunk.get(chunkIdx);
|
|
316
|
+
if (!range) continue;
|
|
317
|
+
this._drawChunk(canvas, chunkIdx, range, step, dpr, halfHeight, bits, waveColor);
|
|
318
|
+
}
|
|
311
319
|
}
|
|
312
320
|
this._dirtyPixels.clear();
|
|
313
321
|
}
|
|
@@ -341,6 +349,45 @@ var DawWaveformElement = class extends LitElement3 {
|
|
|
341
349
|
}
|
|
342
350
|
}
|
|
343
351
|
}
|
|
352
|
+
_drawSegments(canvas, chunkIdx, dpr, halfHeight, bits, waveColor) {
|
|
353
|
+
if (!this.segments) return;
|
|
354
|
+
const ctx = canvas.getContext("2d");
|
|
355
|
+
if (!ctx) return;
|
|
356
|
+
const globalOffset = chunkIdx * MAX_CANVAS_WIDTH;
|
|
357
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH, this.length - globalOffset);
|
|
358
|
+
ctx.resetTransform();
|
|
359
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
360
|
+
ctx.scale(dpr, dpr);
|
|
361
|
+
ctx.fillStyle = waveColor;
|
|
362
|
+
const step = Math.max(1, Math.round(this.barWidth + this.barGap));
|
|
363
|
+
for (const seg of this.segments) {
|
|
364
|
+
if (seg.pixelEnd <= globalOffset || seg.pixelStart >= globalOffset + canvasWidth) continue;
|
|
365
|
+
const localStart = Math.max(0, seg.pixelStart - globalOffset);
|
|
366
|
+
const localEnd = Math.min(canvasWidth, seg.pixelEnd - globalOffset);
|
|
367
|
+
const segPixelWidth = seg.pixelEnd - seg.pixelStart;
|
|
368
|
+
const segPeakWidth = seg.peakEnd - seg.peakStart;
|
|
369
|
+
if (segPixelWidth <= 0 || segPeakWidth <= 0) continue;
|
|
370
|
+
const peaksPerPixel = segPeakWidth / segPixelWidth;
|
|
371
|
+
for (let px = Math.floor(localStart); px < Math.ceil(localEnd); px += step) {
|
|
372
|
+
const pxInSeg = px + globalOffset - seg.pixelStart;
|
|
373
|
+
const peakPos = seg.peakStart + pxInSeg * peaksPerPixel;
|
|
374
|
+
const peakEnd = peakPos + step * peaksPerPixel;
|
|
375
|
+
const peak = aggregatePeaks(this._peaks, bits, Math.floor(peakPos), Math.ceil(peakEnd));
|
|
376
|
+
if (!peak) continue;
|
|
377
|
+
const rects = calculateBarRects(
|
|
378
|
+
px,
|
|
379
|
+
this.barWidth,
|
|
380
|
+
halfHeight,
|
|
381
|
+
peak.min,
|
|
382
|
+
peak.max,
|
|
383
|
+
"normal"
|
|
384
|
+
);
|
|
385
|
+
for (const r of rects) {
|
|
386
|
+
ctx.fillRect(r.x, r.y, r.width, r.height);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
344
391
|
connectedCallback() {
|
|
345
392
|
super.connectedCallback();
|
|
346
393
|
if (this._dirtyPixels.size > 0) {
|
|
@@ -435,6 +482,9 @@ __decorateClass([
|
|
|
435
482
|
__decorateClass([
|
|
436
483
|
property3({ type: Number, attribute: false })
|
|
437
484
|
], DawWaveformElement.prototype, "originX", 2);
|
|
485
|
+
__decorateClass([
|
|
486
|
+
property3({ attribute: false })
|
|
487
|
+
], DawWaveformElement.prototype, "segments", 2);
|
|
438
488
|
DawWaveformElement = __decorateClass([
|
|
439
489
|
customElement3("daw-waveform")
|
|
440
490
|
], DawWaveformElement);
|
|
@@ -502,6 +552,40 @@ var DawPlayheadElement = class extends LitElement4 {
|
|
|
502
552
|
this._line.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
503
553
|
}
|
|
504
554
|
}
|
|
555
|
+
startBeatsAnimation(getTime, bpm, ppqn, ticksPerPixel) {
|
|
556
|
+
const ticksPerSecond = bpm * ppqn / 60;
|
|
557
|
+
this._animation.start(() => {
|
|
558
|
+
const time = getTime();
|
|
559
|
+
const px = time * ticksPerSecond / ticksPerPixel;
|
|
560
|
+
if (this._line) {
|
|
561
|
+
this._line.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
stopBeatsAnimation(time, bpm, ppqn, ticksPerPixel) {
|
|
566
|
+
this._animation.stop();
|
|
567
|
+
const px = time * bpm * ppqn / (60 * ticksPerPixel);
|
|
568
|
+
if (this._line) {
|
|
569
|
+
this._line.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
startBeatsAnimationWithMap(getTime, secondsToTicks, ticksPerPixel) {
|
|
573
|
+
this._animation.start(() => {
|
|
574
|
+
const time = getTime();
|
|
575
|
+
const tick = secondsToTicks(time);
|
|
576
|
+
const px = tick / ticksPerPixel;
|
|
577
|
+
if (this._line) {
|
|
578
|
+
this._line.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
stopBeatsAnimationWithMap(time, secondsToTicks, ticksPerPixel) {
|
|
583
|
+
this._animation.stop();
|
|
584
|
+
const px = secondsToTicks(time) / ticksPerPixel;
|
|
585
|
+
if (this._line) {
|
|
586
|
+
this._line.style.transform = `translate3d(${px}px, 0, 0)`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
505
589
|
};
|
|
506
590
|
DawPlayheadElement.styles = css2`
|
|
507
591
|
:host {
|
|
@@ -753,11 +837,11 @@ DawStopButtonElement = __decorateClass([
|
|
|
753
837
|
], DawStopButtonElement);
|
|
754
838
|
|
|
755
839
|
// src/elements/daw-editor.ts
|
|
756
|
-
import { LitElement as
|
|
757
|
-
import { customElement as
|
|
840
|
+
import { LitElement as LitElement9, html as html8, css as css8 } from "lit";
|
|
841
|
+
import { customElement as customElement11, property as property7, state as state3 } from "lit/decorators.js";
|
|
758
842
|
import {
|
|
759
|
-
createClip as
|
|
760
|
-
createClipFromSeconds
|
|
843
|
+
createClip as createClip3,
|
|
844
|
+
createClipFromSeconds,
|
|
761
845
|
createTrack as createTrack2,
|
|
762
846
|
clipPixelWidth
|
|
763
847
|
} from "@waveform-playlist/core";
|
|
@@ -1169,6 +1253,19 @@ var PeakPipeline = class {
|
|
|
1169
1253
|
}
|
|
1170
1254
|
return requestedScale;
|
|
1171
1255
|
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Extract peaks at the base scale from cached WaveformData.
|
|
1258
|
+
* Returns null if no cached data exists for this buffer.
|
|
1259
|
+
* Used by variable-tempo segments which handle stretching themselves.
|
|
1260
|
+
*/
|
|
1261
|
+
getBaseScalePeaks(audioBuffer, isMono, offsetSamples, durationSamples) {
|
|
1262
|
+
const cached = this._cache.get(audioBuffer);
|
|
1263
|
+
if (!cached) return null;
|
|
1264
|
+
return {
|
|
1265
|
+
peaks: extractPeaks(cached, cached.scale, isMono, offsetSamples, durationSamples),
|
|
1266
|
+
scale: cached.scale
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1172
1269
|
/**
|
|
1173
1270
|
* Return the coarsest (largest) scale among cached WaveformData entries
|
|
1174
1271
|
* that correspond to the given clip buffers. Returns 0 if none are cached.
|
|
@@ -1474,9 +1571,187 @@ DawTrackControlsElement = __decorateClass([
|
|
|
1474
1571
|
customElement9("daw-track-controls")
|
|
1475
1572
|
], DawTrackControlsElement);
|
|
1476
1573
|
|
|
1574
|
+
// src/elements/daw-grid.ts
|
|
1575
|
+
import { LitElement as LitElement8, html as html7, css as css6 } from "lit";
|
|
1576
|
+
import { customElement as customElement10, property as property6 } from "lit/decorators.js";
|
|
1577
|
+
import { MIN_PIXELS_PER_UNIT } from "@waveform-playlist/core";
|
|
1578
|
+
|
|
1579
|
+
// src/utils/musical-tick-cache.ts
|
|
1580
|
+
import { computeMusicalTicks } from "@waveform-playlist/core";
|
|
1581
|
+
var cachedParams = null;
|
|
1582
|
+
var cachedResult = null;
|
|
1583
|
+
function meterEntriesMatch(a, b) {
|
|
1584
|
+
if (a.length !== b.length) return false;
|
|
1585
|
+
for (let i = 0; i < a.length; i++) {
|
|
1586
|
+
if (a[i].tick !== b[i].tick || a[i].numerator !== b[i].numerator || a[i].denominator !== b[i].denominator)
|
|
1587
|
+
return false;
|
|
1588
|
+
}
|
|
1589
|
+
return true;
|
|
1590
|
+
}
|
|
1591
|
+
function paramsMatch(a, b) {
|
|
1592
|
+
return a.ticksPerPixel === b.ticksPerPixel && a.startPixel === b.startPixel && a.endPixel === b.endPixel && meterEntriesMatch(a.meterEntries, b.meterEntries) && (a.ppqn ?? 960) === (b.ppqn ?? 960);
|
|
1593
|
+
}
|
|
1594
|
+
function getCachedMusicalTicks(params) {
|
|
1595
|
+
if (cachedParams && cachedResult && paramsMatch(cachedParams, params)) {
|
|
1596
|
+
return cachedResult;
|
|
1597
|
+
}
|
|
1598
|
+
cachedResult = computeMusicalTicks(params);
|
|
1599
|
+
cachedParams = {
|
|
1600
|
+
...params,
|
|
1601
|
+
meterEntries: params.meterEntries.map((e) => ({ ...e }))
|
|
1602
|
+
};
|
|
1603
|
+
return cachedResult;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// src/elements/daw-grid.ts
|
|
1607
|
+
var MAX_CANVAS_WIDTH2 = 1e3;
|
|
1608
|
+
var DawGridElement = class extends LitElement8 {
|
|
1609
|
+
constructor() {
|
|
1610
|
+
super(...arguments);
|
|
1611
|
+
this.ticksPerPixel = 24;
|
|
1612
|
+
this.meterEntries = [
|
|
1613
|
+
{ tick: 0, numerator: 4, denominator: 4 }
|
|
1614
|
+
];
|
|
1615
|
+
this.ppqn = 960;
|
|
1616
|
+
this.visibleStart = -Infinity;
|
|
1617
|
+
this.visibleEnd = Infinity;
|
|
1618
|
+
this.length = 0;
|
|
1619
|
+
this.height = 200;
|
|
1620
|
+
this._tickData = null;
|
|
1621
|
+
}
|
|
1622
|
+
willUpdate() {
|
|
1623
|
+
if (this.length > 0) {
|
|
1624
|
+
this._tickData = getCachedMusicalTicks({
|
|
1625
|
+
ticksPerPixel: this.ticksPerPixel,
|
|
1626
|
+
meterEntries: this.meterEntries,
|
|
1627
|
+
ppqn: this.ppqn,
|
|
1628
|
+
startPixel: 0,
|
|
1629
|
+
endPixel: this.length
|
|
1630
|
+
});
|
|
1631
|
+
} else {
|
|
1632
|
+
this._tickData = null;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
render() {
|
|
1636
|
+
if (!this._tickData) return html7``;
|
|
1637
|
+
const totalWidth = this.length;
|
|
1638
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1639
|
+
const indices = getVisibleChunkIndices(
|
|
1640
|
+
totalWidth,
|
|
1641
|
+
MAX_CANVAS_WIDTH2,
|
|
1642
|
+
this.visibleStart,
|
|
1643
|
+
this.visibleEnd
|
|
1644
|
+
);
|
|
1645
|
+
return html7`
|
|
1646
|
+
<div class="container" style="width: ${totalWidth}px; height: ${this.height}px;">
|
|
1647
|
+
${indices.map((i) => {
|
|
1648
|
+
const width = Math.min(MAX_CANVAS_WIDTH2, totalWidth - i * MAX_CANVAS_WIDTH2);
|
|
1649
|
+
return html7`
|
|
1650
|
+
<canvas
|
|
1651
|
+
data-index=${i}
|
|
1652
|
+
width=${width * dpr}
|
|
1653
|
+
height=${this.height * dpr}
|
|
1654
|
+
style="left: ${i * MAX_CANVAS_WIDTH2}px; width: ${width}px; height: ${this.height}px;"
|
|
1655
|
+
></canvas>
|
|
1656
|
+
`;
|
|
1657
|
+
})}
|
|
1658
|
+
</div>
|
|
1659
|
+
`;
|
|
1660
|
+
}
|
|
1661
|
+
updated() {
|
|
1662
|
+
this._drawGrid();
|
|
1663
|
+
}
|
|
1664
|
+
_drawGrid() {
|
|
1665
|
+
if (!this._tickData) return;
|
|
1666
|
+
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
1667
|
+
if (!canvases) return;
|
|
1668
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1669
|
+
const style = getComputedStyle(this);
|
|
1670
|
+
const barHighlight = style.getPropertyValue("--daw-grid-bar-highlight").trim() || "rgba(255,255,255,0.02)";
|
|
1671
|
+
const majorLine = style.getPropertyValue("--daw-grid-major-line").trim() || "rgba(255,255,255,0.1)";
|
|
1672
|
+
const minorLine = style.getPropertyValue("--daw-grid-minor-line").trim() || "rgba(255,255,255,0.06)";
|
|
1673
|
+
const { ticks, pixelsPerQuarterNote } = this._tickData;
|
|
1674
|
+
for (const canvas of canvases) {
|
|
1675
|
+
const idx = Number(canvas.dataset.index);
|
|
1676
|
+
const ctx = canvas.getContext("2d");
|
|
1677
|
+
if (!ctx) continue;
|
|
1678
|
+
const chunkLeft = idx * MAX_CANVAS_WIDTH2;
|
|
1679
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH2, this.length - chunkLeft);
|
|
1680
|
+
ctx.resetTransform();
|
|
1681
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1682
|
+
ctx.scale(dpr, dpr);
|
|
1683
|
+
if (pixelsPerQuarterNote * 4 >= MIN_PIXELS_PER_UNIT) {
|
|
1684
|
+
ctx.fillStyle = barHighlight;
|
|
1685
|
+
const majorTicks = ticks.filter((t) => t.type === "major");
|
|
1686
|
+
for (let i = 0; i < majorTicks.length; i++) {
|
|
1687
|
+
if (majorTicks[i].barIndex % 2 === 1) {
|
|
1688
|
+
const x = majorTicks[i].pixel - chunkLeft;
|
|
1689
|
+
const lastMeter = this.meterEntries[this.meterEntries.length - 1];
|
|
1690
|
+
const lastBarWidth = pixelsPerQuarterNote * lastMeter.numerator * (4 / lastMeter.denominator);
|
|
1691
|
+
const nextX = i + 1 < majorTicks.length ? majorTicks[i + 1].pixel - chunkLeft : x + lastBarWidth;
|
|
1692
|
+
ctx.fillRect(x, 0, nextX - x, this.height);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
ctx.lineWidth = 1;
|
|
1697
|
+
for (const tick of ticks) {
|
|
1698
|
+
if (tick.type === "minorMinor") continue;
|
|
1699
|
+
const localX = tick.pixel - chunkLeft;
|
|
1700
|
+
if (localX < 0 || localX >= canvasWidth) continue;
|
|
1701
|
+
ctx.strokeStyle = tick.type === "major" ? majorLine : minorLine;
|
|
1702
|
+
ctx.beginPath();
|
|
1703
|
+
ctx.moveTo(localX + 0.5, 0);
|
|
1704
|
+
ctx.lineTo(localX + 0.5, this.height);
|
|
1705
|
+
ctx.stroke();
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
DawGridElement.styles = css6`
|
|
1711
|
+
:host {
|
|
1712
|
+
display: block;
|
|
1713
|
+
position: absolute;
|
|
1714
|
+
top: 0;
|
|
1715
|
+
left: 0;
|
|
1716
|
+
pointer-events: none;
|
|
1717
|
+
z-index: 0;
|
|
1718
|
+
}
|
|
1719
|
+
.container {
|
|
1720
|
+
position: relative;
|
|
1721
|
+
}
|
|
1722
|
+
canvas {
|
|
1723
|
+
position: absolute;
|
|
1724
|
+
top: 0;
|
|
1725
|
+
}
|
|
1726
|
+
`;
|
|
1727
|
+
__decorateClass([
|
|
1728
|
+
property6({ type: Number, attribute: false })
|
|
1729
|
+
], DawGridElement.prototype, "ticksPerPixel", 2);
|
|
1730
|
+
__decorateClass([
|
|
1731
|
+
property6({ attribute: false })
|
|
1732
|
+
], DawGridElement.prototype, "meterEntries", 2);
|
|
1733
|
+
__decorateClass([
|
|
1734
|
+
property6({ type: Number, attribute: false })
|
|
1735
|
+
], DawGridElement.prototype, "ppqn", 2);
|
|
1736
|
+
__decorateClass([
|
|
1737
|
+
property6({ type: Number, attribute: false })
|
|
1738
|
+
], DawGridElement.prototype, "visibleStart", 2);
|
|
1739
|
+
__decorateClass([
|
|
1740
|
+
property6({ type: Number, attribute: false })
|
|
1741
|
+
], DawGridElement.prototype, "visibleEnd", 2);
|
|
1742
|
+
__decorateClass([
|
|
1743
|
+
property6({ type: Number, attribute: false })
|
|
1744
|
+
], DawGridElement.prototype, "length", 2);
|
|
1745
|
+
__decorateClass([
|
|
1746
|
+
property6({ type: Number, attribute: false })
|
|
1747
|
+
], DawGridElement.prototype, "height", 2);
|
|
1748
|
+
DawGridElement = __decorateClass([
|
|
1749
|
+
customElement10("daw-grid")
|
|
1750
|
+
], DawGridElement);
|
|
1751
|
+
|
|
1477
1752
|
// src/styles/theme.ts
|
|
1478
|
-
import { css as
|
|
1479
|
-
var hostStyles =
|
|
1753
|
+
import { css as css7 } from "lit";
|
|
1754
|
+
var hostStyles = css7`
|
|
1480
1755
|
:host {
|
|
1481
1756
|
--daw-wave-color: #c49a6c;
|
|
1482
1757
|
--daw-progress-color: #63c75f;
|
|
@@ -1492,7 +1767,7 @@ var hostStyles = css6`
|
|
|
1492
1767
|
--daw-clip-header-text: #e0d4c8;
|
|
1493
1768
|
}
|
|
1494
1769
|
`;
|
|
1495
|
-
var clipStyles =
|
|
1770
|
+
var clipStyles = css7`
|
|
1496
1771
|
.clip-container {
|
|
1497
1772
|
position: absolute;
|
|
1498
1773
|
overflow: hidden;
|
|
@@ -1705,8 +1980,7 @@ var AudioResumeController = class {
|
|
|
1705
1980
|
};
|
|
1706
1981
|
|
|
1707
1982
|
// src/controllers/recording-controller.ts
|
|
1708
|
-
import {
|
|
1709
|
-
import { appendPeaks, concatenateAudioData, createAudioBuffer } from "@waveform-playlist/recording";
|
|
1983
|
+
import { appendPeaks, concatenateAudioData, createAudioBuffer } from "@waveform-playlist/core";
|
|
1710
1984
|
var RecordingController = class {
|
|
1711
1985
|
constructor(host) {
|
|
1712
1986
|
this._sessions = /* @__PURE__ */ new Map();
|
|
@@ -1743,6 +2017,14 @@ var RecordingController = class {
|
|
|
1743
2017
|
const rawCtx = this._host.audioContext;
|
|
1744
2018
|
this._host.resolveAudioContextSampleRate(rawCtx.sampleRate);
|
|
1745
2019
|
if (!this._workletLoadedCtx || this._workletLoadedCtx !== rawCtx) {
|
|
2020
|
+
let recordingProcessorUrl;
|
|
2021
|
+
try {
|
|
2022
|
+
({ recordingProcessorUrl } = await import("@waveform-playlist/worklets"));
|
|
2023
|
+
} catch {
|
|
2024
|
+
throw new Error(
|
|
2025
|
+
"Recording requires @waveform-playlist/worklets. Install it: npm install @waveform-playlist/worklets"
|
|
2026
|
+
);
|
|
2027
|
+
}
|
|
1746
2028
|
await rawCtx.audioWorklet.addModule(recordingProcessorUrl);
|
|
1747
2029
|
this._workletLoadedCtx = rawCtx;
|
|
1748
2030
|
}
|
|
@@ -1993,7 +2275,7 @@ var RecordingController = class {
|
|
|
1993
2275
|
};
|
|
1994
2276
|
|
|
1995
2277
|
// src/interactions/pointer-handler.ts
|
|
1996
|
-
import { pixelsToSeconds } from "@waveform-playlist/core";
|
|
2278
|
+
import { pixelsToSeconds, snapTickToGrid } from "@waveform-playlist/core";
|
|
1997
2279
|
|
|
1998
2280
|
// src/interactions/constants.ts
|
|
1999
2281
|
var DRAG_THRESHOLD = 3;
|
|
@@ -2003,6 +2285,7 @@ var PointerHandler = class {
|
|
|
2003
2285
|
constructor(host) {
|
|
2004
2286
|
this._isDragging = false;
|
|
2005
2287
|
this._dragStartPx = 0;
|
|
2288
|
+
this._dragStartTime = 0;
|
|
2006
2289
|
this._timeline = null;
|
|
2007
2290
|
// Cached from onPointerDown to avoid forced layout reflows at 60fps during drag
|
|
2008
2291
|
this._timelineRect = null;
|
|
@@ -2049,21 +2332,18 @@ var PointerHandler = class {
|
|
|
2049
2332
|
const currentPx = this._pxFromPointer(e);
|
|
2050
2333
|
if (!this._isDragging && Math.abs(currentPx - this._dragStartPx) > DRAG_THRESHOLD) {
|
|
2051
2334
|
this._isDragging = true;
|
|
2335
|
+
this._dragStartTime = this._pxToTime(this._dragStartPx);
|
|
2052
2336
|
}
|
|
2053
2337
|
if (this._isDragging) {
|
|
2054
2338
|
const h = this._host;
|
|
2055
|
-
const startTime =
|
|
2056
|
-
|
|
2057
|
-
h.samplesPerPixel,
|
|
2058
|
-
h.effectiveSampleRate
|
|
2059
|
-
);
|
|
2060
|
-
const endTime = pixelsToSeconds(currentPx, h.samplesPerPixel, h.effectiveSampleRate);
|
|
2339
|
+
const startTime = this._dragStartTime;
|
|
2340
|
+
const endTime = this._pxToTime(currentPx);
|
|
2061
2341
|
h._selectionStartTime = Math.min(startTime, endTime);
|
|
2062
2342
|
h._selectionEndTime = Math.max(startTime, endTime);
|
|
2063
2343
|
const sel = h.shadowRoot?.querySelector("daw-selection");
|
|
2064
2344
|
if (sel) {
|
|
2065
|
-
sel.startPx = h._selectionStartTime
|
|
2066
|
-
sel.endPx = h._selectionEndTime
|
|
2345
|
+
sel.startPx = this._timeToPx(h._selectionStartTime);
|
|
2346
|
+
sel.endPx = this._timeToPx(h._selectionEndTime);
|
|
2067
2347
|
}
|
|
2068
2348
|
}
|
|
2069
2349
|
};
|
|
@@ -2101,6 +2381,23 @@ var PointerHandler = class {
|
|
|
2101
2381
|
}
|
|
2102
2382
|
return e.clientX - this._timelineRect.left;
|
|
2103
2383
|
}
|
|
2384
|
+
_pxToTime(px) {
|
|
2385
|
+
const h = this._host;
|
|
2386
|
+
if (h.scaleMode === "beats") {
|
|
2387
|
+
let tick = px * h.ticksPerPixel;
|
|
2388
|
+
tick = snapTickToGrid(tick, h.snapTo, h._meterEntries, h.ppqn);
|
|
2389
|
+
return h._ticksToSeconds(tick);
|
|
2390
|
+
}
|
|
2391
|
+
return pixelsToSeconds(px, h.samplesPerPixel, h.effectiveSampleRate);
|
|
2392
|
+
}
|
|
2393
|
+
_timeToPx(time) {
|
|
2394
|
+
const h = this._host;
|
|
2395
|
+
if (h.scaleMode === "beats") {
|
|
2396
|
+
const tick = h._secondsToTicks(time);
|
|
2397
|
+
return tick / h.ticksPerPixel;
|
|
2398
|
+
}
|
|
2399
|
+
return time * h.effectiveSampleRate / h.samplesPerPixel;
|
|
2400
|
+
}
|
|
2104
2401
|
_finalizeSelection() {
|
|
2105
2402
|
const h = this._host;
|
|
2106
2403
|
if (h._engine) {
|
|
@@ -2118,7 +2415,7 @@ var PointerHandler = class {
|
|
|
2118
2415
|
_handleSeekClick(e) {
|
|
2119
2416
|
const h = this._host;
|
|
2120
2417
|
const px = this._pxFromPointer(e);
|
|
2121
|
-
const time =
|
|
2418
|
+
const time = this._pxToTime(px);
|
|
2122
2419
|
h._selectionStartTime = 0;
|
|
2123
2420
|
h._selectionEndTime = 0;
|
|
2124
2421
|
if (this._timeline) {
|
|
@@ -2183,6 +2480,7 @@ var PointerHandler = class {
|
|
|
2183
2480
|
};
|
|
2184
2481
|
|
|
2185
2482
|
// src/interactions/clip-pointer-handler.ts
|
|
2483
|
+
import { snapTickToGrid as snapTickToGrid2 } from "@waveform-playlist/core";
|
|
2186
2484
|
var ClipPointerHandler = class {
|
|
2187
2485
|
constructor(host) {
|
|
2188
2486
|
this._mode = null;
|
|
@@ -2190,7 +2488,6 @@ var ClipPointerHandler = class {
|
|
|
2190
2488
|
this._trackId = "";
|
|
2191
2489
|
this._startPx = 0;
|
|
2192
2490
|
this._isDragging = false;
|
|
2193
|
-
this._lastDeltaPx = 0;
|
|
2194
2491
|
this._cumulativeDeltaSamples = 0;
|
|
2195
2492
|
// Trim visual feedback: snapshot of original clip state
|
|
2196
2493
|
this._clipContainer = null;
|
|
@@ -2199,8 +2496,31 @@ var ClipPointerHandler = class {
|
|
|
2199
2496
|
this._originalWidth = 0;
|
|
2200
2497
|
this._originalOffsetSamples = 0;
|
|
2201
2498
|
this._originalDurationSamples = 0;
|
|
2499
|
+
this._originalStartSample = 0;
|
|
2202
2500
|
this._host = host;
|
|
2203
2501
|
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Convert a pixel delta to samples, snapping in tick space when in beats mode.
|
|
2504
|
+
*
|
|
2505
|
+
* The anchor is the absolute sample position being moved (e.g., clip start
|
|
2506
|
+
* for move/left-trim, clip end for right-trim). Snapping the absolute
|
|
2507
|
+
* position — not just the delta — ensures clips land exactly on grid lines
|
|
2508
|
+
* even if they started off-grid.
|
|
2509
|
+
*/
|
|
2510
|
+
_snapDeltaToSamples(totalDeltaPx, anchorSample) {
|
|
2511
|
+
const h = this._host;
|
|
2512
|
+
if (h.scaleMode === "beats") {
|
|
2513
|
+
const anchorSeconds = anchorSample / h.effectiveSampleRate;
|
|
2514
|
+
const anchorTick = h._secondsToTicks(anchorSeconds);
|
|
2515
|
+
const deltaTicks = totalDeltaPx * h.ticksPerPixel;
|
|
2516
|
+
const targetTick = anchorTick + deltaTicks;
|
|
2517
|
+
const snappedTick = h.snapTo !== "off" ? snapTickToGrid2(targetTick, h.snapTo, h._meterEntries, h.ppqn) : targetTick;
|
|
2518
|
+
const snappedSeconds = h._ticksToSeconds(snappedTick);
|
|
2519
|
+
const snappedSample = Math.round(snappedSeconds * h.effectiveSampleRate);
|
|
2520
|
+
return snappedSample - anchorSample;
|
|
2521
|
+
}
|
|
2522
|
+
return Math.round(totalDeltaPx * h.renderSamplesPerPixel);
|
|
2523
|
+
}
|
|
2204
2524
|
/** Returns true if a drag interaction is currently in progress. */
|
|
2205
2525
|
get isActive() {
|
|
2206
2526
|
return this._mode !== null;
|
|
@@ -2237,10 +2557,16 @@ var ClipPointerHandler = class {
|
|
|
2237
2557
|
this._trackId = trackId;
|
|
2238
2558
|
this._startPx = e.clientX;
|
|
2239
2559
|
this._isDragging = false;
|
|
2240
|
-
this._lastDeltaPx = 0;
|
|
2241
2560
|
this._cumulativeDeltaSamples = 0;
|
|
2242
|
-
|
|
2243
|
-
|
|
2561
|
+
const engine = this._host.engine;
|
|
2562
|
+
if (engine) {
|
|
2563
|
+
const bounds = engine.getClipBounds(trackId, clipId);
|
|
2564
|
+
if (bounds) {
|
|
2565
|
+
this._originalStartSample = bounds.startSample;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if (engine) {
|
|
2569
|
+
engine.beginTransaction();
|
|
2244
2570
|
} else {
|
|
2245
2571
|
console.warn(
|
|
2246
2572
|
"[dawcore] beginDrag: engine unavailable, drag mutations will not be grouped for undo"
|
|
@@ -2257,9 +2583,9 @@ var ClipPointerHandler = class {
|
|
|
2257
2583
|
} else {
|
|
2258
2584
|
console.warn("[dawcore] clip container not found for trim visual feedback: " + clipId);
|
|
2259
2585
|
}
|
|
2260
|
-
const
|
|
2261
|
-
if (
|
|
2262
|
-
const bounds =
|
|
2586
|
+
const engine2 = this._host.engine;
|
|
2587
|
+
if (engine2) {
|
|
2588
|
+
const bounds = engine2.getClipBounds(trackId, clipId);
|
|
2263
2589
|
if (bounds) {
|
|
2264
2590
|
this._originalOffsetSamples = bounds.offsetSamples;
|
|
2265
2591
|
this._originalDurationSamples = bounds.durationSamples;
|
|
@@ -2281,21 +2607,33 @@ var ClipPointerHandler = class {
|
|
|
2281
2607
|
const engine = this._host.engine;
|
|
2282
2608
|
if (!engine) return;
|
|
2283
2609
|
if (this._mode === "move") {
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2610
|
+
const totalSnappedDelta = this._snapDeltaToSamples(totalDeltaPx, this._originalStartSample);
|
|
2611
|
+
const incrementalDeltaSamples = totalSnappedDelta - this._cumulativeDeltaSamples;
|
|
2612
|
+
if (incrementalDeltaSamples !== 0) {
|
|
2613
|
+
const applied = engine.moveClip(this._trackId, this._clipId, incrementalDeltaSamples, true);
|
|
2614
|
+
this._cumulativeDeltaSamples += applied;
|
|
2615
|
+
}
|
|
2289
2616
|
} else {
|
|
2290
2617
|
const boundary = this._mode === "trim-left" ? "left" : "right";
|
|
2291
|
-
const
|
|
2618
|
+
const anchor = boundary === "left" ? this._originalStartSample : this._originalStartSample + this._originalDurationSamples;
|
|
2619
|
+
const rawDeltaSamples = this._snapDeltaToSamples(totalDeltaPx, anchor);
|
|
2292
2620
|
const deltaSamples = engine.constrainTrimDelta(
|
|
2293
2621
|
this._trackId,
|
|
2294
2622
|
this._clipId,
|
|
2295
2623
|
boundary,
|
|
2296
2624
|
rawDeltaSamples
|
|
2297
2625
|
);
|
|
2298
|
-
|
|
2626
|
+
let deltaPx;
|
|
2627
|
+
if (this._host.scaleMode === "beats") {
|
|
2628
|
+
const h = this._host;
|
|
2629
|
+
const anchorSec = anchor / h.effectiveSampleRate;
|
|
2630
|
+
const anchorTick = h._secondsToTicks(anchorSec);
|
|
2631
|
+
const newSec = anchorSec + deltaSamples / h.effectiveSampleRate;
|
|
2632
|
+
const newTick = h._secondsToTicks(newSec);
|
|
2633
|
+
deltaPx = Math.round((newTick - anchorTick) / h.ticksPerPixel);
|
|
2634
|
+
} else {
|
|
2635
|
+
deltaPx = Math.round(deltaSamples / this._host.renderSamplesPerPixel);
|
|
2636
|
+
}
|
|
2299
2637
|
this._cumulativeDeltaSamples = deltaSamples;
|
|
2300
2638
|
if (this._clipContainer) {
|
|
2301
2639
|
if (this._mode === "trim-left") {
|
|
@@ -2427,18 +2765,18 @@ var ClipPointerHandler = class {
|
|
|
2427
2765
|
this._trackId = "";
|
|
2428
2766
|
this._startPx = 0;
|
|
2429
2767
|
this._isDragging = false;
|
|
2430
|
-
this._lastDeltaPx = 0;
|
|
2431
2768
|
this._cumulativeDeltaSamples = 0;
|
|
2432
2769
|
this._clipContainer = null;
|
|
2433
2770
|
this._originalLeft = 0;
|
|
2434
2771
|
this._originalWidth = 0;
|
|
2435
2772
|
this._originalOffsetSamples = 0;
|
|
2436
2773
|
this._originalDurationSamples = 0;
|
|
2774
|
+
this._originalStartSample = 0;
|
|
2437
2775
|
}
|
|
2438
2776
|
};
|
|
2439
2777
|
|
|
2440
2778
|
// src/interactions/file-loader.ts
|
|
2441
|
-
import {
|
|
2779
|
+
import { createClip, createTrack } from "@waveform-playlist/core";
|
|
2442
2780
|
async function loadFiles(host, files) {
|
|
2443
2781
|
if (!files) {
|
|
2444
2782
|
console.warn("[dawcore] loadFiles called with null/undefined");
|
|
@@ -2460,24 +2798,24 @@ async function loadFiles(host, files) {
|
|
|
2460
2798
|
host._audioCache.delete(blobUrl);
|
|
2461
2799
|
host._resolvedSampleRate = audioBuffer.sampleRate;
|
|
2462
2800
|
const name = file.name.replace(/\.\w+$/, "");
|
|
2463
|
-
const clip =
|
|
2801
|
+
const clip = createClip({
|
|
2464
2802
|
audioBuffer,
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2803
|
+
startSample: 0,
|
|
2804
|
+
durationSamples: audioBuffer.length,
|
|
2805
|
+
offsetSamples: 0,
|
|
2468
2806
|
gain: 1,
|
|
2469
2807
|
name,
|
|
2470
2808
|
sampleRate: audioBuffer.sampleRate,
|
|
2471
|
-
|
|
2809
|
+
sourceDurationSamples: audioBuffer.length
|
|
2472
2810
|
});
|
|
2473
2811
|
host._clipBuffers = new Map(host._clipBuffers).set(clip.id, audioBuffer);
|
|
2474
|
-
host._clipOffsets.set(clip.id, {
|
|
2812
|
+
host._clipOffsets = new Map(host._clipOffsets).set(clip.id, {
|
|
2475
2813
|
offsetSamples: clip.offsetSamples,
|
|
2476
2814
|
durationSamples: clip.durationSamples
|
|
2477
2815
|
});
|
|
2478
2816
|
const peakData = await host._peakPipeline.generatePeaks(
|
|
2479
2817
|
audioBuffer,
|
|
2480
|
-
host.
|
|
2818
|
+
host.renderSamplesPerPixel,
|
|
2481
2819
|
host.mono,
|
|
2482
2820
|
clip.offsetSamples,
|
|
2483
2821
|
clip.durationSamples
|
|
@@ -2539,7 +2877,7 @@ async function loadFiles(host, files) {
|
|
|
2539
2877
|
}
|
|
2540
2878
|
|
|
2541
2879
|
// src/interactions/recording-clip.ts
|
|
2542
|
-
import { createClip } from "@waveform-playlist/core";
|
|
2880
|
+
import { createClip as createClip2 } from "@waveform-playlist/core";
|
|
2543
2881
|
function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamples = 0) {
|
|
2544
2882
|
let trimmedBuf = buf;
|
|
2545
2883
|
if (offsetSamples > 0 && offsetSamples < buf.length) {
|
|
@@ -2554,7 +2892,7 @@ function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamp
|
|
|
2554
2892
|
}
|
|
2555
2893
|
trimmedBuf = trimmed;
|
|
2556
2894
|
}
|
|
2557
|
-
const clip =
|
|
2895
|
+
const clip = createClip2({
|
|
2558
2896
|
audioBuffer: trimmedBuf,
|
|
2559
2897
|
startSample,
|
|
2560
2898
|
durationSamples: durSamples,
|
|
@@ -2722,13 +3060,13 @@ function syncPeaksForChangedClips(host, tracks) {
|
|
|
2722
3060
|
continue;
|
|
2723
3061
|
}
|
|
2724
3062
|
host._clipBuffers = new Map(host._clipBuffers).set(clip.id, audioBuffer);
|
|
2725
|
-
host._clipOffsets.set(clip.id, {
|
|
3063
|
+
host._clipOffsets = new Map(host._clipOffsets).set(clip.id, {
|
|
2726
3064
|
offsetSamples: clip.offsetSamples,
|
|
2727
3065
|
durationSamples: clip.durationSamples
|
|
2728
3066
|
});
|
|
2729
3067
|
host._peakPipeline.generatePeaks(
|
|
2730
3068
|
audioBuffer,
|
|
2731
|
-
host.
|
|
3069
|
+
host.renderSamplesPerPixel,
|
|
2732
3070
|
host.mono,
|
|
2733
3071
|
clip.offsetSamples,
|
|
2734
3072
|
clip.durationSamples
|
|
@@ -2803,7 +3141,7 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
2803
3141
|
}
|
|
2804
3142
|
|
|
2805
3143
|
// src/elements/daw-editor.ts
|
|
2806
|
-
var DawEditorElement = class extends
|
|
3144
|
+
var DawEditorElement = class extends LitElement9 {
|
|
2807
3145
|
constructor() {
|
|
2808
3146
|
super(...arguments);
|
|
2809
3147
|
this._samplesPerPixel = 1024;
|
|
@@ -2816,6 +3154,12 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
2816
3154
|
this.clipHeaders = false;
|
|
2817
3155
|
this.clipHeaderHeight = 20;
|
|
2818
3156
|
this.interactiveClips = false;
|
|
3157
|
+
this.scaleMode = "temporal";
|
|
3158
|
+
this._ticksPerPixel = 24;
|
|
3159
|
+
this._bpm = 120;
|
|
3160
|
+
this.timeSignature = [4, 4];
|
|
3161
|
+
this._ppqn = 960;
|
|
3162
|
+
this.snapTo = "off";
|
|
2819
3163
|
this.sampleRate = 48e3;
|
|
2820
3164
|
/** Resolved sample rate — falls back to sampleRate property until first audio decode. */
|
|
2821
3165
|
this._resolvedSampleRate = null;
|
|
@@ -2834,6 +3178,9 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
2834
3178
|
this._externalAudioContext = null;
|
|
2835
3179
|
this._ownedAudioContext = null;
|
|
2836
3180
|
this._engine = null;
|
|
3181
|
+
this._adapter = null;
|
|
3182
|
+
this._warnedMissingTicksToSeconds = false;
|
|
3183
|
+
this._warnedMissingSecondsToTicks = false;
|
|
2837
3184
|
this._enginePromise = null;
|
|
2838
3185
|
this._audioCache = /* @__PURE__ */ new Map();
|
|
2839
3186
|
this._peaksCache = /* @__PURE__ */ new Map();
|
|
@@ -2978,6 +3325,41 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
2978
3325
|
this._samplesPerPixel = clamped;
|
|
2979
3326
|
this.requestUpdate("samplesPerPixel", old);
|
|
2980
3327
|
}
|
|
3328
|
+
get ticksPerPixel() {
|
|
3329
|
+
return this._ticksPerPixel;
|
|
3330
|
+
}
|
|
3331
|
+
set ticksPerPixel(value) {
|
|
3332
|
+
const old = this._ticksPerPixel;
|
|
3333
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
3334
|
+
this._ticksPerPixel = value;
|
|
3335
|
+
this.requestUpdate("ticksPerPixel", old);
|
|
3336
|
+
}
|
|
3337
|
+
get bpm() {
|
|
3338
|
+
return this._bpm;
|
|
3339
|
+
}
|
|
3340
|
+
set bpm(value) {
|
|
3341
|
+
const old = this._bpm;
|
|
3342
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
3343
|
+
this._bpm = value;
|
|
3344
|
+
if (this._engine) {
|
|
3345
|
+
this._engine.setTempo(value);
|
|
3346
|
+
}
|
|
3347
|
+
this.requestUpdate("bpm", old);
|
|
3348
|
+
}
|
|
3349
|
+
/** MeterEntries for grid/ruler: explicit meterEntries if set, otherwise derived from timeSignature. */
|
|
3350
|
+
get _meterEntries() {
|
|
3351
|
+
if (this.meterEntries && this.meterEntries.length > 0) return this.meterEntries;
|
|
3352
|
+
return [{ tick: 0, numerator: this.timeSignature[0], denominator: this.timeSignature[1] }];
|
|
3353
|
+
}
|
|
3354
|
+
get ppqn() {
|
|
3355
|
+
return this._ppqn;
|
|
3356
|
+
}
|
|
3357
|
+
set ppqn(value) {
|
|
3358
|
+
const old = this._ppqn;
|
|
3359
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
3360
|
+
this._ppqn = value;
|
|
3361
|
+
this.requestUpdate("ppqn", old);
|
|
3362
|
+
}
|
|
2981
3363
|
/** Set an AudioContext to use for all audio operations. Must be set before tracks load. */
|
|
2982
3364
|
set audioContext(ctx) {
|
|
2983
3365
|
if (ctx && ctx.state === "closed") {
|
|
@@ -3009,6 +3391,13 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3009
3391
|
get engine() {
|
|
3010
3392
|
return this._engine;
|
|
3011
3393
|
}
|
|
3394
|
+
/** The adapter's Transport — use for tempo, metronome, and effects. */
|
|
3395
|
+
get transport() {
|
|
3396
|
+
return this._adapter?.transport ?? null;
|
|
3397
|
+
}
|
|
3398
|
+
get renderSamplesPerPixel() {
|
|
3399
|
+
return this._renderSpp;
|
|
3400
|
+
}
|
|
3012
3401
|
/** Re-extract peaks for a clip at new offset/duration from cached WaveformData. */
|
|
3013
3402
|
reextractClipPeaks(clipId, offsetSamples, durationSamples) {
|
|
3014
3403
|
const buf = this._clipBuffers.get(clipId);
|
|
@@ -3017,7 +3406,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3017
3406
|
const singleClipOffsets = /* @__PURE__ */ new Map([[clipId, { offsetSamples, durationSamples }]]);
|
|
3018
3407
|
const result = this._peakPipeline.reextractPeaks(
|
|
3019
3408
|
singleClipBuffers,
|
|
3020
|
-
this.
|
|
3409
|
+
this._renderSpp,
|
|
3021
3410
|
this.mono,
|
|
3022
3411
|
singleClipOffsets
|
|
3023
3412
|
);
|
|
@@ -3031,9 +3420,59 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3031
3420
|
resolveAudioContextSampleRate(rate) {
|
|
3032
3421
|
if (!this._resolvedSampleRate) this._resolvedSampleRate = rate;
|
|
3033
3422
|
}
|
|
3423
|
+
/**
|
|
3424
|
+
* In beats mode, derive samplesPerPixel from ticksPerPixel so that
|
|
3425
|
+
* clip positions, waveforms, and the tick-space grid all align.
|
|
3426
|
+
*/
|
|
3427
|
+
get _renderSpp() {
|
|
3428
|
+
if (this.scaleMode === "beats") {
|
|
3429
|
+
const spp = Math.ceil(
|
|
3430
|
+
60 * this.effectiveSampleRate * this.ticksPerPixel / (this.ppqn * this.bpm)
|
|
3431
|
+
);
|
|
3432
|
+
return this._minSamplesPerPixel > 0 ? Math.max(spp, this._minSamplesPerPixel) : spp;
|
|
3433
|
+
}
|
|
3434
|
+
return this.samplesPerPixel;
|
|
3435
|
+
}
|
|
3436
|
+
/** Convert seconds to ticks — uses callback if provided, otherwise single-BPM fallback. */
|
|
3437
|
+
_secondsToTicks(seconds) {
|
|
3438
|
+
if (this.secondsToTicks) {
|
|
3439
|
+
if (!this.ticksToSeconds && !this._warnedMissingTicksToSeconds) {
|
|
3440
|
+
this._warnedMissingTicksToSeconds = true;
|
|
3441
|
+
console.warn(
|
|
3442
|
+
"[waveform-playlist] daw-editor: secondsToTicks is set but ticksToSeconds is missing. Both callbacks are required for variable tempo."
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
return this.secondsToTicks(seconds);
|
|
3446
|
+
}
|
|
3447
|
+
return seconds * this.bpm * this.ppqn / 60;
|
|
3448
|
+
}
|
|
3449
|
+
/** Convert ticks to seconds — uses callback if provided, otherwise single-BPM fallback. */
|
|
3450
|
+
_ticksToSeconds(ticks) {
|
|
3451
|
+
if (this.ticksToSeconds) {
|
|
3452
|
+
if (!this.secondsToTicks && !this._warnedMissingSecondsToTicks) {
|
|
3453
|
+
this._warnedMissingSecondsToTicks = true;
|
|
3454
|
+
console.warn(
|
|
3455
|
+
"[waveform-playlist] daw-editor: ticksToSeconds is set but secondsToTicks is missing. Both callbacks are required for variable tempo."
|
|
3456
|
+
);
|
|
3457
|
+
}
|
|
3458
|
+
return this.ticksToSeconds(ticks);
|
|
3459
|
+
}
|
|
3460
|
+
return ticks * 60 / (this.bpm * this.ppqn);
|
|
3461
|
+
}
|
|
3034
3462
|
get _totalWidth() {
|
|
3463
|
+
if (this.scaleMode === "beats") {
|
|
3464
|
+
const contentTicks = this._secondsToTicks(this._duration);
|
|
3465
|
+
const [num] = this.timeSignature;
|
|
3466
|
+
const minTicks = 32 * num * this.ppqn;
|
|
3467
|
+
return Math.ceil(Math.max(contentTicks, minTicks) / this.ticksPerPixel);
|
|
3468
|
+
}
|
|
3035
3469
|
return Math.ceil(this._duration * this.effectiveSampleRate / this.samplesPerPixel);
|
|
3036
3470
|
}
|
|
3471
|
+
/** Grid height when no tracks exist — matches scroll area's rendered height. */
|
|
3472
|
+
get _emptyGridHeight() {
|
|
3473
|
+
const scrollArea = this.shadowRoot?.querySelector(".scroll-area");
|
|
3474
|
+
return scrollArea?.clientHeight ?? 200;
|
|
3475
|
+
}
|
|
3037
3476
|
_setSelectedTrackId(trackId) {
|
|
3038
3477
|
this._selectedTrackId = trackId;
|
|
3039
3478
|
}
|
|
@@ -3119,13 +3558,14 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3119
3558
|
if (changedProperties.has("eagerResume")) {
|
|
3120
3559
|
this._audioResume.target = this.eagerResume;
|
|
3121
3560
|
}
|
|
3122
|
-
if (changedProperties.has("samplesPerPixel") && this._isPlaying) {
|
|
3561
|
+
if ((changedProperties.has("samplesPerPixel") || changedProperties.has("ticksPerPixel") || changedProperties.has("bpm") || changedProperties.has("secondsToTicks")) && this._isPlaying) {
|
|
3123
3562
|
this._startPlayhead();
|
|
3124
3563
|
}
|
|
3125
|
-
|
|
3564
|
+
const zoomChanged = changedProperties.has("samplesPerPixel") || changedProperties.has("ticksPerPixel") || changedProperties.has("bpm") || changedProperties.has("scaleMode") || changedProperties.has("secondsToTicks");
|
|
3565
|
+
if (zoomChanged && this._clipBuffers.size > 0) {
|
|
3126
3566
|
const re = this._peakPipeline.reextractPeaks(
|
|
3127
3567
|
this._clipBuffers,
|
|
3128
|
-
this.
|
|
3568
|
+
this._renderSpp,
|
|
3129
3569
|
this.mono,
|
|
3130
3570
|
this._clipOffsets
|
|
3131
3571
|
);
|
|
@@ -3234,7 +3674,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3234
3674
|
}
|
|
3235
3675
|
if (waveformData) {
|
|
3236
3676
|
const wdRate = waveformData.sample_rate;
|
|
3237
|
-
const clip2 =
|
|
3677
|
+
const clip2 = createClip3({
|
|
3238
3678
|
waveformData,
|
|
3239
3679
|
startSample: Math.round(clipDesc.start * wdRate),
|
|
3240
3680
|
durationSamples: Math.round((clipDesc.duration || waveformData.duration) * wdRate),
|
|
@@ -3244,7 +3684,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3244
3684
|
sampleRate: wdRate,
|
|
3245
3685
|
sourceDurationSamples: Math.ceil(waveformData.duration * wdRate)
|
|
3246
3686
|
});
|
|
3247
|
-
const effectiveScale = Math.max(this.
|
|
3687
|
+
const effectiveScale = Math.max(this._renderSpp, waveformData.scale);
|
|
3248
3688
|
const peakData2 = extractPeaks(
|
|
3249
3689
|
waveformData,
|
|
3250
3690
|
effectiveScale,
|
|
@@ -3293,7 +3733,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3293
3733
|
}
|
|
3294
3734
|
const audioBuffer = await audioPromise;
|
|
3295
3735
|
this._resolvedSampleRate = audioBuffer.sampleRate;
|
|
3296
|
-
const clip =
|
|
3736
|
+
const clip = createClipFromSeconds({
|
|
3297
3737
|
audioBuffer,
|
|
3298
3738
|
startTime: clipDesc.start,
|
|
3299
3739
|
duration: clipDesc.duration || audioBuffer.duration,
|
|
@@ -3310,7 +3750,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3310
3750
|
});
|
|
3311
3751
|
const peakData = await this._peakPipeline.generatePeaks(
|
|
3312
3752
|
audioBuffer,
|
|
3313
|
-
this.
|
|
3753
|
+
this._renderSpp,
|
|
3314
3754
|
this.mono,
|
|
3315
3755
|
clip.offsetSamples,
|
|
3316
3756
|
clip.durationSamples
|
|
@@ -3408,10 +3848,14 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3408
3848
|
import("@dawcore/transport")
|
|
3409
3849
|
]);
|
|
3410
3850
|
const adapter = new NativePlayoutAdapter(this.audioContext);
|
|
3851
|
+
this._adapter = adapter;
|
|
3852
|
+
adapter.setTempo(this._bpm);
|
|
3411
3853
|
const engine = new PlaylistEngine({
|
|
3412
3854
|
adapter,
|
|
3413
3855
|
sampleRate: this.effectiveSampleRate,
|
|
3414
3856
|
samplesPerPixel: this.samplesPerPixel,
|
|
3857
|
+
bpm: this._bpm,
|
|
3858
|
+
ppqn: this._ppqn,
|
|
3415
3859
|
zoomLevels: [256, 512, 1024, 2048, 4096, 8192, this.samplesPerPixel].filter((v, i, a) => a.indexOf(v) === i).sort((a, b) => a - b)
|
|
3416
3860
|
});
|
|
3417
3861
|
let lastTracksVersion = -1;
|
|
@@ -3444,6 +3888,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3444
3888
|
this._engine.dispose();
|
|
3445
3889
|
this._engine = null;
|
|
3446
3890
|
}
|
|
3891
|
+
this._adapter = null;
|
|
3447
3892
|
this._enginePromise = null;
|
|
3448
3893
|
}
|
|
3449
3894
|
async loadFiles(files) {
|
|
@@ -3581,12 +4026,13 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3581
4026
|
if (!rs) return "";
|
|
3582
4027
|
const audibleSamples = Math.max(0, rs.totalSamples - rs.latencySamples);
|
|
3583
4028
|
if (audibleSamples === 0) return "";
|
|
3584
|
-
const
|
|
3585
|
-
const
|
|
3586
|
-
const
|
|
4029
|
+
const renderSpp = this._renderSpp;
|
|
4030
|
+
const latencyPixels = Math.floor(rs.latencySamples / renderSpp);
|
|
4031
|
+
const left = Math.floor(rs.startSample / renderSpp);
|
|
4032
|
+
const w = Math.floor(audibleSamples / renderSpp);
|
|
3587
4033
|
return rs.peaks.map((chPeaks, ch) => {
|
|
3588
4034
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
3589
|
-
return
|
|
4035
|
+
return html8`
|
|
3590
4036
|
<daw-waveform
|
|
3591
4037
|
data-recording-track=${trackId}
|
|
3592
4038
|
data-recording-channel=${ch}
|
|
@@ -3609,19 +4055,39 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3609
4055
|
if (!playhead || !this._engine) return;
|
|
3610
4056
|
const engine = this._engine;
|
|
3611
4057
|
const ctx = this.audioContext;
|
|
3612
|
-
|
|
3613
|
-
() =>
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
4058
|
+
if (this.scaleMode === "beats") {
|
|
4059
|
+
const secondsToTicksFn = (s) => this._secondsToTicks(s);
|
|
4060
|
+
playhead.startBeatsAnimationWithMap(
|
|
4061
|
+
() => {
|
|
4062
|
+
const latency = "outputLatency" in ctx ? ctx.outputLatency : 0;
|
|
4063
|
+
return Math.max(0, engine.getCurrentTime() - latency);
|
|
4064
|
+
},
|
|
4065
|
+
secondsToTicksFn,
|
|
4066
|
+
this.ticksPerPixel
|
|
4067
|
+
);
|
|
4068
|
+
} else {
|
|
4069
|
+
playhead.startAnimation(
|
|
4070
|
+
() => {
|
|
4071
|
+
const latency = "outputLatency" in ctx ? ctx.outputLatency : 0;
|
|
4072
|
+
return Math.max(0, engine.getCurrentTime() - latency);
|
|
4073
|
+
},
|
|
4074
|
+
this.effectiveSampleRate,
|
|
4075
|
+
this.samplesPerPixel
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
3620
4078
|
}
|
|
3621
4079
|
_stopPlayhead() {
|
|
3622
4080
|
const playhead = this._getPlayhead();
|
|
3623
4081
|
if (!playhead) return;
|
|
3624
|
-
|
|
4082
|
+
if (this.scaleMode === "beats") {
|
|
4083
|
+
playhead.stopBeatsAnimationWithMap(
|
|
4084
|
+
this._currentTime,
|
|
4085
|
+
(s) => this._secondsToTicks(s),
|
|
4086
|
+
this.ticksPerPixel
|
|
4087
|
+
);
|
|
4088
|
+
} else {
|
|
4089
|
+
playhead.stopAnimation(this._currentTime, this.effectiveSampleRate, this.samplesPerPixel);
|
|
4090
|
+
}
|
|
3625
4091
|
}
|
|
3626
4092
|
_getPlayhead() {
|
|
3627
4093
|
return this.shadowRoot?.querySelector("daw-playhead");
|
|
@@ -3642,8 +4108,18 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3642
4108
|
// --- Render ---
|
|
3643
4109
|
render() {
|
|
3644
4110
|
const sr = this.effectiveSampleRate;
|
|
3645
|
-
const
|
|
3646
|
-
|
|
4111
|
+
const spp = this._renderSpp;
|
|
4112
|
+
let selStartPx;
|
|
4113
|
+
let selEndPx;
|
|
4114
|
+
if (this.scaleMode === "beats") {
|
|
4115
|
+
const startTick = this._secondsToTicks(this._selectionStartTime);
|
|
4116
|
+
const endTick = this._secondsToTicks(this._selectionEndTime);
|
|
4117
|
+
selStartPx = startTick / this.ticksPerPixel;
|
|
4118
|
+
selEndPx = endTick / this.ticksPerPixel;
|
|
4119
|
+
} else {
|
|
4120
|
+
selStartPx = this._selectionStartTime * sr / spp;
|
|
4121
|
+
selEndPx = this._selectionEndTime * sr / spp;
|
|
4122
|
+
}
|
|
3647
4123
|
const orderedTracks = this._getOrderedTracks().map(([trackId, track]) => {
|
|
3648
4124
|
const descriptor = this._tracks.get(trackId);
|
|
3649
4125
|
const firstPeaks = track.clips.map((c) => this._peaksData.get(c.id)).find((p) => p && p.data.length > 0);
|
|
@@ -3657,11 +4133,11 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3657
4133
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
3658
4134
|
};
|
|
3659
4135
|
});
|
|
3660
|
-
return
|
|
3661
|
-
${orderedTracks.length > 0 ?
|
|
3662
|
-
${this.timescale ?
|
|
4136
|
+
return html8`
|
|
4137
|
+
${orderedTracks.length > 0 ? html8`<div class="controls-column">
|
|
4138
|
+
${this.timescale ? html8`<div style="height: 30px;"></div>` : ""}
|
|
3663
4139
|
${orderedTracks.map(
|
|
3664
|
-
(t) =>
|
|
4140
|
+
(t) => html8`
|
|
3665
4141
|
<daw-track-controls
|
|
3666
4142
|
style="height: ${t.trackHeight}px;"
|
|
3667
4143
|
.trackId=${t.trackId}
|
|
@@ -3684,16 +4160,31 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3684
4160
|
@dragleave=${this._onDragLeave}
|
|
3685
4161
|
@drop=${this._onDrop}
|
|
3686
4162
|
>
|
|
3687
|
-
${orderedTracks.length > 0 && this.timescale ?
|
|
3688
|
-
.samplesPerPixel=${
|
|
4163
|
+
${(orderedTracks.length > 0 || this.scaleMode === "beats") && this.timescale ? html8`<daw-ruler
|
|
4164
|
+
.samplesPerPixel=${spp}
|
|
3689
4165
|
.sampleRate=${this.effectiveSampleRate}
|
|
3690
4166
|
.duration=${this._duration}
|
|
4167
|
+
.scaleMode=${this.scaleMode}
|
|
4168
|
+
.ticksPerPixel=${this.ticksPerPixel}
|
|
4169
|
+
.meterEntries=${this._meterEntries}
|
|
4170
|
+
.ppqn=${this.ppqn}
|
|
4171
|
+
.totalWidth=${this._totalWidth}
|
|
3691
4172
|
></daw-ruler>` : ""}
|
|
3692
|
-
${
|
|
4173
|
+
${this.scaleMode === "beats" ? html8`<daw-grid
|
|
4174
|
+
style="top: ${this.timescale ? 30 : 0}px;"
|
|
4175
|
+
.ticksPerPixel=${this.ticksPerPixel}
|
|
4176
|
+
.meterEntries=${this._meterEntries}
|
|
4177
|
+
.ppqn=${this.ppqn}
|
|
4178
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
4179
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
4180
|
+
.length=${this._totalWidth}
|
|
4181
|
+
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight + 1, 0) : this._emptyGridHeight}
|
|
4182
|
+
></daw-grid>` : ""}
|
|
4183
|
+
${orderedTracks.length > 0 || this.scaleMode === "beats" ? html8`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
3693
4184
|
<daw-playhead></daw-playhead>` : ""}
|
|
3694
4185
|
${orderedTracks.map((t) => {
|
|
3695
4186
|
const channelHeight = this.waveHeight;
|
|
3696
|
-
return
|
|
4187
|
+
return html8`
|
|
3697
4188
|
<div
|
|
3698
4189
|
class="track-row ${t.trackId === this._selectedTrackId ? "selected" : ""}"
|
|
3699
4190
|
style="height: ${t.trackHeight}px;"
|
|
@@ -3701,21 +4192,67 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3701
4192
|
>
|
|
3702
4193
|
${t.track.clips.map((clip) => {
|
|
3703
4194
|
const peakData = this._peaksData.get(clip.id);
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
this.
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
4195
|
+
let clipLeft;
|
|
4196
|
+
let width;
|
|
4197
|
+
if (this.scaleMode === "beats") {
|
|
4198
|
+
const startTick = clip.startTick !== void 0 ? clip.startTick : this._secondsToTicks(clip.startSample / sr);
|
|
4199
|
+
const durSec = clip.durationSamples / sr;
|
|
4200
|
+
const startSec = clip.startTick !== void 0 ? this._ticksToSeconds(clip.startTick) : clip.startSample / sr;
|
|
4201
|
+
const endTick = this._secondsToTicks(startSec + durSec);
|
|
4202
|
+
clipLeft = Math.round(startTick / this.ticksPerPixel);
|
|
4203
|
+
width = Math.round(endTick / this.ticksPerPixel) - clipLeft;
|
|
4204
|
+
} else {
|
|
4205
|
+
clipLeft = Math.floor(clip.startSample / spp);
|
|
4206
|
+
width = clipPixelWidth(clip.startSample, clip.durationSamples, spp);
|
|
4207
|
+
}
|
|
4208
|
+
let clipSegments;
|
|
4209
|
+
let segmentChannels;
|
|
4210
|
+
if (this.scaleMode === "beats" && this.secondsToTicks) {
|
|
4211
|
+
const audioBuffer = this._clipBuffers.get(clip.id);
|
|
4212
|
+
const basePeaks = audioBuffer ? this._peakPipeline.getBaseScalePeaks(
|
|
4213
|
+
audioBuffer,
|
|
4214
|
+
this.mono,
|
|
4215
|
+
clip.offsetSamples,
|
|
4216
|
+
clip.durationSamples
|
|
4217
|
+
) : null;
|
|
4218
|
+
if (basePeaks) {
|
|
4219
|
+
const baseScale = basePeaks.scale;
|
|
4220
|
+
segmentChannels = basePeaks.peaks.data;
|
|
4221
|
+
const MIN_RENDER_STEP = 80;
|
|
4222
|
+
const stepTicks = Math.max(MIN_RENDER_STEP, Math.ceil(this.ticksPerPixel));
|
|
4223
|
+
const startSec = clip.startTick !== void 0 ? this._ticksToSeconds(clip.startTick) : clip.startSample / sr;
|
|
4224
|
+
const clipOffsetSec = clip.offsetSamples / sr;
|
|
4225
|
+
const segStartTick = clip.startTick !== void 0 ? clip.startTick : this._secondsToTicks(startSec);
|
|
4226
|
+
const endTick = this._secondsToTicks(startSec + clip.durationSamples / sr);
|
|
4227
|
+
clipSegments = [];
|
|
4228
|
+
for (let tick = segStartTick; tick < endTick; tick += stepTicks) {
|
|
4229
|
+
const segEndTick = Math.min(tick + stepTicks, endTick);
|
|
4230
|
+
const segStartAudioSec = this._ticksToSeconds(tick) - startSec + clipOffsetSec;
|
|
4231
|
+
const segEndAudioSec = this._ticksToSeconds(segEndTick) - startSec + clipOffsetSec;
|
|
4232
|
+
const segStartSample = Math.round(segStartAudioSec * sr);
|
|
4233
|
+
const segEndSample = Math.round(segEndAudioSec * sr);
|
|
4234
|
+
const totalPeaks = clip.durationSamples / baseScale;
|
|
4235
|
+
clipSegments.push({
|
|
4236
|
+
peakStart: Math.max(0, (segStartSample - clip.offsetSamples) / baseScale),
|
|
4237
|
+
peakEnd: Math.min(
|
|
4238
|
+
totalPeaks,
|
|
4239
|
+
(segEndSample - clip.offsetSamples) / baseScale
|
|
4240
|
+
),
|
|
4241
|
+
pixelStart: (tick - segStartTick) / this.ticksPerPixel,
|
|
4242
|
+
pixelEnd: (segEndTick - segStartTick) / this.ticksPerPixel
|
|
4243
|
+
});
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
const channels = segmentChannels ?? peakData?.data ?? [new Int16Array(0)];
|
|
3711
4248
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
3712
4249
|
const chH = this.waveHeight;
|
|
3713
|
-
return
|
|
4250
|
+
return html8` <div
|
|
3714
4251
|
class="clip-container"
|
|
3715
4252
|
style="left:${clipLeft}px;top:0;width:${width}px;height:${t.trackHeight}px;"
|
|
3716
4253
|
data-clip-id=${clip.id}
|
|
3717
4254
|
>
|
|
3718
|
-
${hdrH > 0 ?
|
|
4255
|
+
${hdrH > 0 ? html8`<div
|
|
3719
4256
|
class="clip-header"
|
|
3720
4257
|
data-clip-id=${clip.id}
|
|
3721
4258
|
data-track-id=${t.trackId}
|
|
@@ -3724,7 +4261,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3724
4261
|
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
3725
4262
|
</div>` : ""}
|
|
3726
4263
|
${channels.map(
|
|
3727
|
-
(chPeaks, chIdx) =>
|
|
4264
|
+
(chPeaks, chIdx) => html8` <daw-waveform
|
|
3728
4265
|
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
3729
4266
|
.peaks=${chPeaks}
|
|
3730
4267
|
.length=${peakData?.length ?? width}
|
|
@@ -3734,9 +4271,10 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3734
4271
|
.visibleStart=${this._viewport.visibleStart}
|
|
3735
4272
|
.visibleEnd=${this._viewport.visibleEnd}
|
|
3736
4273
|
.originX=${clipLeft}
|
|
4274
|
+
.segments=${clipSegments}
|
|
3737
4275
|
></daw-waveform>`
|
|
3738
4276
|
)}
|
|
3739
|
-
${this.interactiveClips ?
|
|
4277
|
+
${this.interactiveClips ? html8` <div
|
|
3740
4278
|
class="clip-boundary"
|
|
3741
4279
|
data-boundary-edge="left"
|
|
3742
4280
|
data-clip-id=${clip.id}
|
|
@@ -3762,7 +4300,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3762
4300
|
};
|
|
3763
4301
|
DawEditorElement.styles = [
|
|
3764
4302
|
hostStyles,
|
|
3765
|
-
|
|
4303
|
+
css8`
|
|
3766
4304
|
:host {
|
|
3767
4305
|
display: flex;
|
|
3768
4306
|
position: relative;
|
|
@@ -3792,6 +4330,15 @@ DawEditorElement.styles = [
|
|
|
3792
4330
|
.track-row.selected {
|
|
3793
4331
|
background: rgba(99, 199, 95, 0.08);
|
|
3794
4332
|
}
|
|
4333
|
+
:host([scale-mode='beats']) .track-row {
|
|
4334
|
+
background: transparent;
|
|
4335
|
+
}
|
|
4336
|
+
:host([scale-mode='beats']) .clip-container {
|
|
4337
|
+
background: var(--daw-track-background, #16213e);
|
|
4338
|
+
}
|
|
4339
|
+
:host([scale-mode='beats']) .track-row.selected .clip-container {
|
|
4340
|
+
box-shadow: inset 0 0 0 1000px rgba(99, 199, 95, 0.06);
|
|
4341
|
+
}
|
|
3795
4342
|
.timeline.drag-over {
|
|
3796
4343
|
outline: 2px dashed var(--daw-selection-color, rgba(99, 199, 95, 0.3));
|
|
3797
4344
|
outline-offset: -2px;
|
|
@@ -3801,37 +4348,64 @@ DawEditorElement.styles = [
|
|
|
3801
4348
|
];
|
|
3802
4349
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
3803
4350
|
__decorateClass([
|
|
3804
|
-
|
|
4351
|
+
property7({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
3805
4352
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
3806
4353
|
__decorateClass([
|
|
3807
|
-
|
|
4354
|
+
property7({ type: Number, attribute: "wave-height" })
|
|
3808
4355
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
3809
4356
|
__decorateClass([
|
|
3810
|
-
|
|
4357
|
+
property7({ type: Boolean })
|
|
3811
4358
|
], DawEditorElement.prototype, "timescale", 2);
|
|
3812
4359
|
__decorateClass([
|
|
3813
|
-
|
|
4360
|
+
property7({ type: Boolean })
|
|
3814
4361
|
], DawEditorElement.prototype, "mono", 2);
|
|
3815
4362
|
__decorateClass([
|
|
3816
|
-
|
|
4363
|
+
property7({ type: Number, attribute: "bar-width" })
|
|
3817
4364
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
3818
4365
|
__decorateClass([
|
|
3819
|
-
|
|
4366
|
+
property7({ type: Number, attribute: "bar-gap" })
|
|
3820
4367
|
], DawEditorElement.prototype, "barGap", 2);
|
|
3821
4368
|
__decorateClass([
|
|
3822
|
-
|
|
4369
|
+
property7({ type: Boolean, attribute: "file-drop" })
|
|
3823
4370
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
3824
4371
|
__decorateClass([
|
|
3825
|
-
|
|
4372
|
+
property7({ type: Boolean, attribute: "clip-headers" })
|
|
3826
4373
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
3827
4374
|
__decorateClass([
|
|
3828
|
-
|
|
4375
|
+
property7({ type: Number, attribute: "clip-header-height" })
|
|
3829
4376
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
3830
4377
|
__decorateClass([
|
|
3831
|
-
|
|
4378
|
+
property7({ type: Boolean, attribute: "interactive-clips" })
|
|
3832
4379
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
3833
4380
|
__decorateClass([
|
|
3834
|
-
|
|
4381
|
+
property7({ type: String, attribute: "scale-mode" })
|
|
4382
|
+
], DawEditorElement.prototype, "scaleMode", 2);
|
|
4383
|
+
__decorateClass([
|
|
4384
|
+
property7({ type: Number, attribute: "ticks-per-pixel", noAccessor: true })
|
|
4385
|
+
], DawEditorElement.prototype, "ticksPerPixel", 1);
|
|
4386
|
+
__decorateClass([
|
|
4387
|
+
property7({ type: Number, noAccessor: true })
|
|
4388
|
+
], DawEditorElement.prototype, "bpm", 1);
|
|
4389
|
+
__decorateClass([
|
|
4390
|
+
property7({ attribute: false })
|
|
4391
|
+
], DawEditorElement.prototype, "timeSignature", 2);
|
|
4392
|
+
__decorateClass([
|
|
4393
|
+
property7({ attribute: false })
|
|
4394
|
+
], DawEditorElement.prototype, "meterEntries", 2);
|
|
4395
|
+
__decorateClass([
|
|
4396
|
+
property7({ type: Number, noAccessor: true })
|
|
4397
|
+
], DawEditorElement.prototype, "ppqn", 1);
|
|
4398
|
+
__decorateClass([
|
|
4399
|
+
property7({ type: String, attribute: "snap-to" })
|
|
4400
|
+
], DawEditorElement.prototype, "snapTo", 2);
|
|
4401
|
+
__decorateClass([
|
|
4402
|
+
property7({ attribute: false })
|
|
4403
|
+
], DawEditorElement.prototype, "secondsToTicks", 2);
|
|
4404
|
+
__decorateClass([
|
|
4405
|
+
property7({ attribute: false })
|
|
4406
|
+
], DawEditorElement.prototype, "ticksToSeconds", 2);
|
|
4407
|
+
__decorateClass([
|
|
4408
|
+
property7({ type: Number, attribute: "sample-rate" })
|
|
3835
4409
|
], DawEditorElement.prototype, "sampleRate", 2);
|
|
3836
4410
|
__decorateClass([
|
|
3837
4411
|
state3()
|
|
@@ -3855,15 +4429,15 @@ __decorateClass([
|
|
|
3855
4429
|
state3()
|
|
3856
4430
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
3857
4431
|
__decorateClass([
|
|
3858
|
-
|
|
4432
|
+
property7({ attribute: "eager-resume" })
|
|
3859
4433
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
3860
4434
|
DawEditorElement = __decorateClass([
|
|
3861
|
-
|
|
4435
|
+
customElement11("daw-editor")
|
|
3862
4436
|
], DawEditorElement);
|
|
3863
4437
|
|
|
3864
4438
|
// src/elements/daw-ruler.ts
|
|
3865
|
-
import { LitElement as
|
|
3866
|
-
import { customElement as
|
|
4439
|
+
import { LitElement as LitElement10, html as html9, css as css9 } from "lit";
|
|
4440
|
+
import { customElement as customElement12, property as property8 } from "lit/decorators.js";
|
|
3867
4441
|
|
|
3868
4442
|
// src/utils/time-format.ts
|
|
3869
4443
|
function formatTime(milliseconds) {
|
|
@@ -3914,18 +4488,36 @@ function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight
|
|
|
3914
4488
|
}
|
|
3915
4489
|
|
|
3916
4490
|
// src/elements/daw-ruler.ts
|
|
3917
|
-
var
|
|
3918
|
-
var DawRulerElement = class extends
|
|
4491
|
+
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
4492
|
+
var DawRulerElement = class extends LitElement10 {
|
|
3919
4493
|
constructor() {
|
|
3920
4494
|
super(...arguments);
|
|
3921
4495
|
this.samplesPerPixel = 1024;
|
|
3922
4496
|
this.sampleRate = 48e3;
|
|
3923
4497
|
this.duration = 0;
|
|
3924
4498
|
this.rulerHeight = 30;
|
|
4499
|
+
this.scaleMode = "temporal";
|
|
4500
|
+
this.ticksPerPixel = 4;
|
|
4501
|
+
this.meterEntries = [
|
|
4502
|
+
{ tick: 0, numerator: 4, denominator: 4 }
|
|
4503
|
+
];
|
|
4504
|
+
this.ppqn = 960;
|
|
4505
|
+
this.totalWidth = 0;
|
|
3925
4506
|
this._tickData = null;
|
|
4507
|
+
this._musicalTickData = null;
|
|
3926
4508
|
}
|
|
3927
4509
|
willUpdate() {
|
|
3928
|
-
if (this.
|
|
4510
|
+
if (this.scaleMode === "beats" && this.totalWidth > 0) {
|
|
4511
|
+
this._musicalTickData = getCachedMusicalTicks({
|
|
4512
|
+
meterEntries: this.meterEntries,
|
|
4513
|
+
ticksPerPixel: this.ticksPerPixel,
|
|
4514
|
+
startPixel: 0,
|
|
4515
|
+
endPixel: this.totalWidth,
|
|
4516
|
+
ppqn: this.ppqn
|
|
4517
|
+
});
|
|
4518
|
+
this._tickData = null;
|
|
4519
|
+
} else if (this.duration > 0) {
|
|
4520
|
+
this._musicalTickData = null;
|
|
3929
4521
|
this._tickData = computeTemporalTicks(
|
|
3930
4522
|
this.samplesPerPixel,
|
|
3931
4523
|
this.sampleRate,
|
|
@@ -3933,30 +4525,39 @@ var DawRulerElement = class extends LitElement9 {
|
|
|
3933
4525
|
this.rulerHeight
|
|
3934
4526
|
);
|
|
3935
4527
|
} else {
|
|
4528
|
+
this._musicalTickData = null;
|
|
3936
4529
|
this._tickData = null;
|
|
3937
4530
|
}
|
|
3938
4531
|
}
|
|
3939
4532
|
render() {
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
const totalChunks = Math.ceil(widthX /
|
|
4533
|
+
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
4534
|
+
if (widthX <= 0) return html9``;
|
|
4535
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH3);
|
|
3943
4536
|
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
3944
4537
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
3945
|
-
|
|
4538
|
+
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
4539
|
+
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
4540
|
+
return html9`
|
|
3946
4541
|
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
3947
4542
|
${indices.map((i) => {
|
|
3948
|
-
const width = Math.min(
|
|
3949
|
-
return
|
|
4543
|
+
const width = Math.min(MAX_CANVAS_WIDTH3, widthX - i * MAX_CANVAS_WIDTH3);
|
|
4544
|
+
return html9`
|
|
3950
4545
|
<canvas
|
|
3951
4546
|
data-index=${i}
|
|
3952
4547
|
width=${width * dpr}
|
|
3953
4548
|
height=${this.rulerHeight * dpr}
|
|
3954
|
-
style="left: ${i *
|
|
4549
|
+
style="left: ${i * MAX_CANVAS_WIDTH3}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
3955
4550
|
></canvas>
|
|
3956
4551
|
`;
|
|
3957
4552
|
})}
|
|
3958
|
-
${
|
|
3959
|
-
(
|
|
4553
|
+
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
4554
|
+
(t) => html9`<span
|
|
4555
|
+
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
4556
|
+
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
4557
|
+
>${t.label}</span
|
|
4558
|
+
>`
|
|
4559
|
+
) : temporalLabels.map(
|
|
4560
|
+
({ pix, text }) => html9`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
3960
4561
|
)}
|
|
3961
4562
|
</div>
|
|
3962
4563
|
`;
|
|
@@ -3965,37 +4566,49 @@ var DawRulerElement = class extends LitElement9 {
|
|
|
3965
4566
|
this._drawTicks();
|
|
3966
4567
|
}
|
|
3967
4568
|
_drawTicks() {
|
|
3968
|
-
if (!this._tickData) return;
|
|
3969
4569
|
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
3970
4570
|
if (!canvases) return;
|
|
3971
4571
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
3972
4572
|
const rulerColor = getComputedStyle(this).getPropertyValue("--daw-ruler-color").trim() || "#c49a6c";
|
|
4573
|
+
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
3973
4574
|
for (const canvas of canvases) {
|
|
3974
4575
|
const idx = Number(canvas.dataset.index);
|
|
3975
4576
|
const ctx = canvas.getContext("2d");
|
|
3976
4577
|
if (!ctx) continue;
|
|
3977
|
-
const canvasWidth = Math.min(
|
|
3978
|
-
|
|
3979
|
-
this._tickData.widthX - idx * MAX_CANVAS_WIDTH2
|
|
3980
|
-
);
|
|
3981
|
-
const globalOffset = idx * MAX_CANVAS_WIDTH2;
|
|
4578
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH3, widthX - idx * MAX_CANVAS_WIDTH3);
|
|
4579
|
+
const globalOffset = idx * MAX_CANVAS_WIDTH3;
|
|
3982
4580
|
ctx.resetTransform();
|
|
3983
4581
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
3984
4582
|
ctx.scale(dpr, dpr);
|
|
3985
4583
|
ctx.strokeStyle = rulerColor;
|
|
3986
4584
|
ctx.lineWidth = 1;
|
|
3987
|
-
|
|
3988
|
-
const
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
4585
|
+
if (this.scaleMode === "beats" && this._musicalTickData) {
|
|
4586
|
+
const h = this.rulerHeight;
|
|
4587
|
+
for (const tick of this._musicalTickData.ticks) {
|
|
4588
|
+
const localX = tick.pixel - globalOffset;
|
|
4589
|
+
if (localX < 0 || localX >= canvasWidth) continue;
|
|
4590
|
+
const tickH = tick.type === "major" ? h * 0.6 : tick.type === "minor" ? h * 0.35 : h * 0.15;
|
|
4591
|
+
ctx.globalAlpha = tick.type === "major" ? 1 : 0.5;
|
|
4592
|
+
ctx.beginPath();
|
|
4593
|
+
ctx.moveTo(localX + 0.5, h);
|
|
4594
|
+
ctx.lineTo(localX + 0.5, h - tickH);
|
|
4595
|
+
ctx.stroke();
|
|
4596
|
+
}
|
|
4597
|
+
ctx.globalAlpha = 1;
|
|
4598
|
+
} else if (this._tickData) {
|
|
4599
|
+
for (const [pix, height] of this._tickData.canvasInfo) {
|
|
4600
|
+
const localX = pix - globalOffset;
|
|
4601
|
+
if (localX < 0 || localX >= canvasWidth) continue;
|
|
4602
|
+
ctx.beginPath();
|
|
4603
|
+
ctx.moveTo(localX + 0.5, this.rulerHeight);
|
|
4604
|
+
ctx.lineTo(localX + 0.5, this.rulerHeight - height);
|
|
4605
|
+
ctx.stroke();
|
|
4606
|
+
}
|
|
3994
4607
|
}
|
|
3995
4608
|
}
|
|
3996
4609
|
}
|
|
3997
4610
|
};
|
|
3998
|
-
DawRulerElement.styles =
|
|
4611
|
+
DawRulerElement.styles = css9`
|
|
3999
4612
|
:host {
|
|
4000
4613
|
display: block;
|
|
4001
4614
|
position: relative;
|
|
@@ -4011,31 +4624,50 @@ DawRulerElement.styles = css8`
|
|
|
4011
4624
|
.label {
|
|
4012
4625
|
position: absolute;
|
|
4013
4626
|
font-size: 0.7rem;
|
|
4627
|
+
line-height: 1;
|
|
4014
4628
|
white-space: nowrap;
|
|
4015
4629
|
color: var(--daw-ruler-color, #c49a6c);
|
|
4016
|
-
top:
|
|
4630
|
+
top: 1px;
|
|
4631
|
+
}
|
|
4632
|
+
.label.centered {
|
|
4633
|
+
transform: translateX(-50%);
|
|
4017
4634
|
}
|
|
4018
4635
|
`;
|
|
4019
4636
|
__decorateClass([
|
|
4020
|
-
|
|
4637
|
+
property8({ type: Number, attribute: false })
|
|
4021
4638
|
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
4022
4639
|
__decorateClass([
|
|
4023
|
-
|
|
4640
|
+
property8({ type: Number, attribute: false })
|
|
4024
4641
|
], DawRulerElement.prototype, "sampleRate", 2);
|
|
4025
4642
|
__decorateClass([
|
|
4026
|
-
|
|
4643
|
+
property8({ type: Number, attribute: false })
|
|
4027
4644
|
], DawRulerElement.prototype, "duration", 2);
|
|
4028
4645
|
__decorateClass([
|
|
4029
|
-
|
|
4646
|
+
property8({ type: Number, attribute: false })
|
|
4030
4647
|
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
4648
|
+
__decorateClass([
|
|
4649
|
+
property8({ type: String, attribute: false })
|
|
4650
|
+
], DawRulerElement.prototype, "scaleMode", 2);
|
|
4651
|
+
__decorateClass([
|
|
4652
|
+
property8({ type: Number, attribute: false })
|
|
4653
|
+
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
4654
|
+
__decorateClass([
|
|
4655
|
+
property8({ attribute: false })
|
|
4656
|
+
], DawRulerElement.prototype, "meterEntries", 2);
|
|
4657
|
+
__decorateClass([
|
|
4658
|
+
property8({ type: Number, attribute: false })
|
|
4659
|
+
], DawRulerElement.prototype, "ppqn", 2);
|
|
4660
|
+
__decorateClass([
|
|
4661
|
+
property8({ type: Number, attribute: false })
|
|
4662
|
+
], DawRulerElement.prototype, "totalWidth", 2);
|
|
4031
4663
|
DawRulerElement = __decorateClass([
|
|
4032
|
-
|
|
4664
|
+
customElement12("daw-ruler")
|
|
4033
4665
|
], DawRulerElement);
|
|
4034
4666
|
|
|
4035
4667
|
// src/elements/daw-selection.ts
|
|
4036
|
-
import { LitElement as
|
|
4037
|
-
import { customElement as
|
|
4038
|
-
var DawSelectionElement = class extends
|
|
4668
|
+
import { LitElement as LitElement11, html as html10, css as css10 } from "lit";
|
|
4669
|
+
import { customElement as customElement13, property as property9 } from "lit/decorators.js";
|
|
4670
|
+
var DawSelectionElement = class extends LitElement11 {
|
|
4039
4671
|
constructor() {
|
|
4040
4672
|
super(...arguments);
|
|
4041
4673
|
this.startPx = 0;
|
|
@@ -4044,11 +4676,11 @@ var DawSelectionElement = class extends LitElement10 {
|
|
|
4044
4676
|
render() {
|
|
4045
4677
|
const left = Math.min(this.startPx, this.endPx);
|
|
4046
4678
|
const width = Math.abs(this.endPx - this.startPx);
|
|
4047
|
-
if (width === 0) return
|
|
4048
|
-
return
|
|
4679
|
+
if (width === 0) return html10``;
|
|
4680
|
+
return html10`<div style="left: ${left}px; width: ${width}px;"></div>`;
|
|
4049
4681
|
}
|
|
4050
4682
|
};
|
|
4051
|
-
DawSelectionElement.styles =
|
|
4683
|
+
DawSelectionElement.styles = css10`
|
|
4052
4684
|
:host {
|
|
4053
4685
|
position: absolute;
|
|
4054
4686
|
top: 0;
|
|
@@ -4065,18 +4697,18 @@ DawSelectionElement.styles = css9`
|
|
|
4065
4697
|
}
|
|
4066
4698
|
`;
|
|
4067
4699
|
__decorateClass([
|
|
4068
|
-
|
|
4700
|
+
property9({ type: Number, attribute: false })
|
|
4069
4701
|
], DawSelectionElement.prototype, "startPx", 2);
|
|
4070
4702
|
__decorateClass([
|
|
4071
|
-
|
|
4703
|
+
property9({ type: Number, attribute: false })
|
|
4072
4704
|
], DawSelectionElement.prototype, "endPx", 2);
|
|
4073
4705
|
DawSelectionElement = __decorateClass([
|
|
4074
|
-
|
|
4706
|
+
customElement13("daw-selection")
|
|
4075
4707
|
], DawSelectionElement);
|
|
4076
4708
|
|
|
4077
4709
|
// src/elements/daw-record-button.ts
|
|
4078
|
-
import { html as
|
|
4079
|
-
import { customElement as
|
|
4710
|
+
import { html as html11, css as css11 } from "lit";
|
|
4711
|
+
import { customElement as customElement14, state as state4 } from "lit/decorators.js";
|
|
4080
4712
|
var DawRecordButtonElement = class extends DawTransportButton {
|
|
4081
4713
|
constructor() {
|
|
4082
4714
|
super(...arguments);
|
|
@@ -4117,7 +4749,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
4117
4749
|
}
|
|
4118
4750
|
}
|
|
4119
4751
|
render() {
|
|
4120
|
-
return
|
|
4752
|
+
return html11`
|
|
4121
4753
|
<button part="button" ?data-recording=${this._isRecording} @click=${this._onClick}>
|
|
4122
4754
|
<slot>Record</slot>
|
|
4123
4755
|
</button>
|
|
@@ -4137,7 +4769,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
4137
4769
|
};
|
|
4138
4770
|
DawRecordButtonElement.styles = [
|
|
4139
4771
|
DawTransportButton.styles,
|
|
4140
|
-
|
|
4772
|
+
css11`
|
|
4141
4773
|
button[data-recording] {
|
|
4142
4774
|
color: #d08070;
|
|
4143
4775
|
border-color: #d08070;
|
|
@@ -4149,14 +4781,14 @@ __decorateClass([
|
|
|
4149
4781
|
state4()
|
|
4150
4782
|
], DawRecordButtonElement.prototype, "_isRecording", 2);
|
|
4151
4783
|
DawRecordButtonElement = __decorateClass([
|
|
4152
|
-
|
|
4784
|
+
customElement14("daw-record-button")
|
|
4153
4785
|
], DawRecordButtonElement);
|
|
4154
4786
|
|
|
4155
4787
|
// src/elements/daw-keyboard-shortcuts.ts
|
|
4156
|
-
import { LitElement as
|
|
4157
|
-
import { customElement as
|
|
4788
|
+
import { LitElement as LitElement12 } from "lit";
|
|
4789
|
+
import { customElement as customElement15, property as property10 } from "lit/decorators.js";
|
|
4158
4790
|
import { handleKeyboardEvent } from "@waveform-playlist/core";
|
|
4159
|
-
var DawKeyboardShortcutsElement = class extends
|
|
4791
|
+
var DawKeyboardShortcutsElement = class extends LitElement12 {
|
|
4160
4792
|
constructor() {
|
|
4161
4793
|
super(...arguments);
|
|
4162
4794
|
this.playback = false;
|
|
@@ -4310,22 +4942,23 @@ var DawKeyboardShortcutsElement = class extends LitElement11 {
|
|
|
4310
4942
|
}
|
|
4311
4943
|
};
|
|
4312
4944
|
__decorateClass([
|
|
4313
|
-
|
|
4945
|
+
property10({ type: Boolean })
|
|
4314
4946
|
], DawKeyboardShortcutsElement.prototype, "playback", 2);
|
|
4315
4947
|
__decorateClass([
|
|
4316
|
-
|
|
4948
|
+
property10({ type: Boolean })
|
|
4317
4949
|
], DawKeyboardShortcutsElement.prototype, "splitting", 2);
|
|
4318
4950
|
__decorateClass([
|
|
4319
|
-
|
|
4951
|
+
property10({ type: Boolean })
|
|
4320
4952
|
], DawKeyboardShortcutsElement.prototype, "undo", 2);
|
|
4321
4953
|
DawKeyboardShortcutsElement = __decorateClass([
|
|
4322
|
-
|
|
4954
|
+
customElement15("daw-keyboard-shortcuts")
|
|
4323
4955
|
], DawKeyboardShortcutsElement);
|
|
4324
4956
|
export {
|
|
4325
4957
|
AudioResumeController,
|
|
4326
4958
|
ClipPointerHandler,
|
|
4327
4959
|
DawClipElement,
|
|
4328
4960
|
DawEditorElement,
|
|
4961
|
+
DawGridElement,
|
|
4329
4962
|
DawKeyboardShortcutsElement,
|
|
4330
4963
|
DawPauseButtonElement,
|
|
4331
4964
|
DawPlayButtonElement,
|