@dawcore/components 0.0.8 → 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 +822 -185
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +805 -169
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -13
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;
|
|
@@ -3429,8 +3873,8 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3429
3873
|
syncPeaksForChangedClips(this, engineState.tracks);
|
|
3430
3874
|
}
|
|
3431
3875
|
});
|
|
3432
|
-
engine.on("
|
|
3433
|
-
this._currentTime =
|
|
3876
|
+
engine.on("pause", () => {
|
|
3877
|
+
this._currentTime = engine.getCurrentTime();
|
|
3434
3878
|
});
|
|
3435
3879
|
engine.on("stop", () => {
|
|
3436
3880
|
this._currentTime = engine.getCurrentTime();
|
|
@@ -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) {
|
|
@@ -3530,7 +3975,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3530
3975
|
splitAtPlayhead() {
|
|
3531
3976
|
return splitAtPlayhead({
|
|
3532
3977
|
effectiveSampleRate: this.effectiveSampleRate,
|
|
3533
|
-
currentTime: this.
|
|
3978
|
+
currentTime: this.currentTime,
|
|
3534
3979
|
isPlaying: this._isPlaying,
|
|
3535
3980
|
engine: this._engine,
|
|
3536
3981
|
dispatchEvent: (e) => this.dispatchEvent(e),
|
|
@@ -3548,6 +3993,9 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3548
3993
|
});
|
|
3549
3994
|
}
|
|
3550
3995
|
get currentTime() {
|
|
3996
|
+
if (this._isPlaying && this._engine) {
|
|
3997
|
+
return this._engine.getCurrentTime();
|
|
3998
|
+
}
|
|
3551
3999
|
return this._currentTime;
|
|
3552
4000
|
}
|
|
3553
4001
|
get isRecording() {
|
|
@@ -3578,12 +4026,13 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3578
4026
|
if (!rs) return "";
|
|
3579
4027
|
const audibleSamples = Math.max(0, rs.totalSamples - rs.latencySamples);
|
|
3580
4028
|
if (audibleSamples === 0) return "";
|
|
3581
|
-
const
|
|
3582
|
-
const
|
|
3583
|
-
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);
|
|
3584
4033
|
return rs.peaks.map((chPeaks, ch) => {
|
|
3585
4034
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
3586
|
-
return
|
|
4035
|
+
return html8`
|
|
3587
4036
|
<daw-waveform
|
|
3588
4037
|
data-recording-track=${trackId}
|
|
3589
4038
|
data-recording-channel=${ch}
|
|
@@ -3606,19 +4055,39 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3606
4055
|
if (!playhead || !this._engine) return;
|
|
3607
4056
|
const engine = this._engine;
|
|
3608
4057
|
const ctx = this.audioContext;
|
|
3609
|
-
|
|
3610
|
-
() =>
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
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
|
+
}
|
|
3617
4078
|
}
|
|
3618
4079
|
_stopPlayhead() {
|
|
3619
4080
|
const playhead = this._getPlayhead();
|
|
3620
4081
|
if (!playhead) return;
|
|
3621
|
-
|
|
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
|
+
}
|
|
3622
4091
|
}
|
|
3623
4092
|
_getPlayhead() {
|
|
3624
4093
|
return this.shadowRoot?.querySelector("daw-playhead");
|
|
@@ -3639,8 +4108,18 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3639
4108
|
// --- Render ---
|
|
3640
4109
|
render() {
|
|
3641
4110
|
const sr = this.effectiveSampleRate;
|
|
3642
|
-
const
|
|
3643
|
-
|
|
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
|
+
}
|
|
3644
4123
|
const orderedTracks = this._getOrderedTracks().map(([trackId, track]) => {
|
|
3645
4124
|
const descriptor = this._tracks.get(trackId);
|
|
3646
4125
|
const firstPeaks = track.clips.map((c) => this._peaksData.get(c.id)).find((p) => p && p.data.length > 0);
|
|
@@ -3654,11 +4133,11 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3654
4133
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
3655
4134
|
};
|
|
3656
4135
|
});
|
|
3657
|
-
return
|
|
3658
|
-
${orderedTracks.length > 0 ?
|
|
3659
|
-
${this.timescale ?
|
|
4136
|
+
return html8`
|
|
4137
|
+
${orderedTracks.length > 0 ? html8`<div class="controls-column">
|
|
4138
|
+
${this.timescale ? html8`<div style="height: 30px;"></div>` : ""}
|
|
3660
4139
|
${orderedTracks.map(
|
|
3661
|
-
(t) =>
|
|
4140
|
+
(t) => html8`
|
|
3662
4141
|
<daw-track-controls
|
|
3663
4142
|
style="height: ${t.trackHeight}px;"
|
|
3664
4143
|
.trackId=${t.trackId}
|
|
@@ -3681,16 +4160,31 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3681
4160
|
@dragleave=${this._onDragLeave}
|
|
3682
4161
|
@drop=${this._onDrop}
|
|
3683
4162
|
>
|
|
3684
|
-
${orderedTracks.length > 0 && this.timescale ?
|
|
3685
|
-
.samplesPerPixel=${
|
|
4163
|
+
${(orderedTracks.length > 0 || this.scaleMode === "beats") && this.timescale ? html8`<daw-ruler
|
|
4164
|
+
.samplesPerPixel=${spp}
|
|
3686
4165
|
.sampleRate=${this.effectiveSampleRate}
|
|
3687
4166
|
.duration=${this._duration}
|
|
4167
|
+
.scaleMode=${this.scaleMode}
|
|
4168
|
+
.ticksPerPixel=${this.ticksPerPixel}
|
|
4169
|
+
.meterEntries=${this._meterEntries}
|
|
4170
|
+
.ppqn=${this.ppqn}
|
|
4171
|
+
.totalWidth=${this._totalWidth}
|
|
3688
4172
|
></daw-ruler>` : ""}
|
|
3689
|
-
${
|
|
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>
|
|
3690
4184
|
<daw-playhead></daw-playhead>` : ""}
|
|
3691
4185
|
${orderedTracks.map((t) => {
|
|
3692
4186
|
const channelHeight = this.waveHeight;
|
|
3693
|
-
return
|
|
4187
|
+
return html8`
|
|
3694
4188
|
<div
|
|
3695
4189
|
class="track-row ${t.trackId === this._selectedTrackId ? "selected" : ""}"
|
|
3696
4190
|
style="height: ${t.trackHeight}px;"
|
|
@@ -3698,21 +4192,67 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3698
4192
|
>
|
|
3699
4193
|
${t.track.clips.map((clip) => {
|
|
3700
4194
|
const peakData = this._peaksData.get(clip.id);
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
this.
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
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)];
|
|
3708
4248
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
3709
4249
|
const chH = this.waveHeight;
|
|
3710
|
-
return
|
|
4250
|
+
return html8` <div
|
|
3711
4251
|
class="clip-container"
|
|
3712
4252
|
style="left:${clipLeft}px;top:0;width:${width}px;height:${t.trackHeight}px;"
|
|
3713
4253
|
data-clip-id=${clip.id}
|
|
3714
4254
|
>
|
|
3715
|
-
${hdrH > 0 ?
|
|
4255
|
+
${hdrH > 0 ? html8`<div
|
|
3716
4256
|
class="clip-header"
|
|
3717
4257
|
data-clip-id=${clip.id}
|
|
3718
4258
|
data-track-id=${t.trackId}
|
|
@@ -3721,7 +4261,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3721
4261
|
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
3722
4262
|
</div>` : ""}
|
|
3723
4263
|
${channels.map(
|
|
3724
|
-
(chPeaks, chIdx) =>
|
|
4264
|
+
(chPeaks, chIdx) => html8` <daw-waveform
|
|
3725
4265
|
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
3726
4266
|
.peaks=${chPeaks}
|
|
3727
4267
|
.length=${peakData?.length ?? width}
|
|
@@ -3731,9 +4271,10 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3731
4271
|
.visibleStart=${this._viewport.visibleStart}
|
|
3732
4272
|
.visibleEnd=${this._viewport.visibleEnd}
|
|
3733
4273
|
.originX=${clipLeft}
|
|
4274
|
+
.segments=${clipSegments}
|
|
3734
4275
|
></daw-waveform>`
|
|
3735
4276
|
)}
|
|
3736
|
-
${this.interactiveClips ?
|
|
4277
|
+
${this.interactiveClips ? html8` <div
|
|
3737
4278
|
class="clip-boundary"
|
|
3738
4279
|
data-boundary-edge="left"
|
|
3739
4280
|
data-clip-id=${clip.id}
|
|
@@ -3759,7 +4300,7 @@ var DawEditorElement = class extends LitElement8 {
|
|
|
3759
4300
|
};
|
|
3760
4301
|
DawEditorElement.styles = [
|
|
3761
4302
|
hostStyles,
|
|
3762
|
-
|
|
4303
|
+
css8`
|
|
3763
4304
|
:host {
|
|
3764
4305
|
display: flex;
|
|
3765
4306
|
position: relative;
|
|
@@ -3789,6 +4330,15 @@ DawEditorElement.styles = [
|
|
|
3789
4330
|
.track-row.selected {
|
|
3790
4331
|
background: rgba(99, 199, 95, 0.08);
|
|
3791
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
|
+
}
|
|
3792
4342
|
.timeline.drag-over {
|
|
3793
4343
|
outline: 2px dashed var(--daw-selection-color, rgba(99, 199, 95, 0.3));
|
|
3794
4344
|
outline-offset: -2px;
|
|
@@ -3798,37 +4348,64 @@ DawEditorElement.styles = [
|
|
|
3798
4348
|
];
|
|
3799
4349
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
3800
4350
|
__decorateClass([
|
|
3801
|
-
|
|
4351
|
+
property7({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
3802
4352
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
3803
4353
|
__decorateClass([
|
|
3804
|
-
|
|
4354
|
+
property7({ type: Number, attribute: "wave-height" })
|
|
3805
4355
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
3806
4356
|
__decorateClass([
|
|
3807
|
-
|
|
4357
|
+
property7({ type: Boolean })
|
|
3808
4358
|
], DawEditorElement.prototype, "timescale", 2);
|
|
3809
4359
|
__decorateClass([
|
|
3810
|
-
|
|
4360
|
+
property7({ type: Boolean })
|
|
3811
4361
|
], DawEditorElement.prototype, "mono", 2);
|
|
3812
4362
|
__decorateClass([
|
|
3813
|
-
|
|
4363
|
+
property7({ type: Number, attribute: "bar-width" })
|
|
3814
4364
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
3815
4365
|
__decorateClass([
|
|
3816
|
-
|
|
4366
|
+
property7({ type: Number, attribute: "bar-gap" })
|
|
3817
4367
|
], DawEditorElement.prototype, "barGap", 2);
|
|
3818
4368
|
__decorateClass([
|
|
3819
|
-
|
|
4369
|
+
property7({ type: Boolean, attribute: "file-drop" })
|
|
3820
4370
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
3821
4371
|
__decorateClass([
|
|
3822
|
-
|
|
4372
|
+
property7({ type: Boolean, attribute: "clip-headers" })
|
|
3823
4373
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
3824
4374
|
__decorateClass([
|
|
3825
|
-
|
|
4375
|
+
property7({ type: Number, attribute: "clip-header-height" })
|
|
3826
4376
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
3827
4377
|
__decorateClass([
|
|
3828
|
-
|
|
4378
|
+
property7({ type: Boolean, attribute: "interactive-clips" })
|
|
3829
4379
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
3830
4380
|
__decorateClass([
|
|
3831
|
-
|
|
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" })
|
|
3832
4409
|
], DawEditorElement.prototype, "sampleRate", 2);
|
|
3833
4410
|
__decorateClass([
|
|
3834
4411
|
state3()
|
|
@@ -3852,15 +4429,15 @@ __decorateClass([
|
|
|
3852
4429
|
state3()
|
|
3853
4430
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
3854
4431
|
__decorateClass([
|
|
3855
|
-
|
|
4432
|
+
property7({ attribute: "eager-resume" })
|
|
3856
4433
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
3857
4434
|
DawEditorElement = __decorateClass([
|
|
3858
|
-
|
|
4435
|
+
customElement11("daw-editor")
|
|
3859
4436
|
], DawEditorElement);
|
|
3860
4437
|
|
|
3861
4438
|
// src/elements/daw-ruler.ts
|
|
3862
|
-
import { LitElement as
|
|
3863
|
-
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";
|
|
3864
4441
|
|
|
3865
4442
|
// src/utils/time-format.ts
|
|
3866
4443
|
function formatTime(milliseconds) {
|
|
@@ -3911,18 +4488,36 @@ function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight
|
|
|
3911
4488
|
}
|
|
3912
4489
|
|
|
3913
4490
|
// src/elements/daw-ruler.ts
|
|
3914
|
-
var
|
|
3915
|
-
var DawRulerElement = class extends
|
|
4491
|
+
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
4492
|
+
var DawRulerElement = class extends LitElement10 {
|
|
3916
4493
|
constructor() {
|
|
3917
4494
|
super(...arguments);
|
|
3918
4495
|
this.samplesPerPixel = 1024;
|
|
3919
4496
|
this.sampleRate = 48e3;
|
|
3920
4497
|
this.duration = 0;
|
|
3921
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;
|
|
3922
4506
|
this._tickData = null;
|
|
4507
|
+
this._musicalTickData = null;
|
|
3923
4508
|
}
|
|
3924
4509
|
willUpdate() {
|
|
3925
|
-
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;
|
|
3926
4521
|
this._tickData = computeTemporalTicks(
|
|
3927
4522
|
this.samplesPerPixel,
|
|
3928
4523
|
this.sampleRate,
|
|
@@ -3930,30 +4525,39 @@ var DawRulerElement = class extends LitElement9 {
|
|
|
3930
4525
|
this.rulerHeight
|
|
3931
4526
|
);
|
|
3932
4527
|
} else {
|
|
4528
|
+
this._musicalTickData = null;
|
|
3933
4529
|
this._tickData = null;
|
|
3934
4530
|
}
|
|
3935
4531
|
}
|
|
3936
4532
|
render() {
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
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);
|
|
3940
4536
|
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
3941
4537
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
3942
|
-
|
|
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`
|
|
3943
4541
|
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
3944
4542
|
${indices.map((i) => {
|
|
3945
|
-
const width = Math.min(
|
|
3946
|
-
return
|
|
4543
|
+
const width = Math.min(MAX_CANVAS_WIDTH3, widthX - i * MAX_CANVAS_WIDTH3);
|
|
4544
|
+
return html9`
|
|
3947
4545
|
<canvas
|
|
3948
4546
|
data-index=${i}
|
|
3949
4547
|
width=${width * dpr}
|
|
3950
4548
|
height=${this.rulerHeight * dpr}
|
|
3951
|
-
style="left: ${i *
|
|
4549
|
+
style="left: ${i * MAX_CANVAS_WIDTH3}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
3952
4550
|
></canvas>
|
|
3953
4551
|
`;
|
|
3954
4552
|
})}
|
|
3955
|
-
${
|
|
3956
|
-
(
|
|
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>`
|
|
3957
4561
|
)}
|
|
3958
4562
|
</div>
|
|
3959
4563
|
`;
|
|
@@ -3962,37 +4566,49 @@ var DawRulerElement = class extends LitElement9 {
|
|
|
3962
4566
|
this._drawTicks();
|
|
3963
4567
|
}
|
|
3964
4568
|
_drawTicks() {
|
|
3965
|
-
if (!this._tickData) return;
|
|
3966
4569
|
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
3967
4570
|
if (!canvases) return;
|
|
3968
4571
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
3969
4572
|
const rulerColor = getComputedStyle(this).getPropertyValue("--daw-ruler-color").trim() || "#c49a6c";
|
|
4573
|
+
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
3970
4574
|
for (const canvas of canvases) {
|
|
3971
4575
|
const idx = Number(canvas.dataset.index);
|
|
3972
4576
|
const ctx = canvas.getContext("2d");
|
|
3973
4577
|
if (!ctx) continue;
|
|
3974
|
-
const canvasWidth = Math.min(
|
|
3975
|
-
|
|
3976
|
-
this._tickData.widthX - idx * MAX_CANVAS_WIDTH2
|
|
3977
|
-
);
|
|
3978
|
-
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;
|
|
3979
4580
|
ctx.resetTransform();
|
|
3980
4581
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
3981
4582
|
ctx.scale(dpr, dpr);
|
|
3982
4583
|
ctx.strokeStyle = rulerColor;
|
|
3983
4584
|
ctx.lineWidth = 1;
|
|
3984
|
-
|
|
3985
|
-
const
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
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
|
+
}
|
|
3991
4607
|
}
|
|
3992
4608
|
}
|
|
3993
4609
|
}
|
|
3994
4610
|
};
|
|
3995
|
-
DawRulerElement.styles =
|
|
4611
|
+
DawRulerElement.styles = css9`
|
|
3996
4612
|
:host {
|
|
3997
4613
|
display: block;
|
|
3998
4614
|
position: relative;
|
|
@@ -4008,31 +4624,50 @@ DawRulerElement.styles = css8`
|
|
|
4008
4624
|
.label {
|
|
4009
4625
|
position: absolute;
|
|
4010
4626
|
font-size: 0.7rem;
|
|
4627
|
+
line-height: 1;
|
|
4011
4628
|
white-space: nowrap;
|
|
4012
4629
|
color: var(--daw-ruler-color, #c49a6c);
|
|
4013
|
-
top:
|
|
4630
|
+
top: 1px;
|
|
4631
|
+
}
|
|
4632
|
+
.label.centered {
|
|
4633
|
+
transform: translateX(-50%);
|
|
4014
4634
|
}
|
|
4015
4635
|
`;
|
|
4016
4636
|
__decorateClass([
|
|
4017
|
-
|
|
4637
|
+
property8({ type: Number, attribute: false })
|
|
4018
4638
|
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
4019
4639
|
__decorateClass([
|
|
4020
|
-
|
|
4640
|
+
property8({ type: Number, attribute: false })
|
|
4021
4641
|
], DawRulerElement.prototype, "sampleRate", 2);
|
|
4022
4642
|
__decorateClass([
|
|
4023
|
-
|
|
4643
|
+
property8({ type: Number, attribute: false })
|
|
4024
4644
|
], DawRulerElement.prototype, "duration", 2);
|
|
4025
4645
|
__decorateClass([
|
|
4026
|
-
|
|
4646
|
+
property8({ type: Number, attribute: false })
|
|
4027
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);
|
|
4028
4663
|
DawRulerElement = __decorateClass([
|
|
4029
|
-
|
|
4664
|
+
customElement12("daw-ruler")
|
|
4030
4665
|
], DawRulerElement);
|
|
4031
4666
|
|
|
4032
4667
|
// src/elements/daw-selection.ts
|
|
4033
|
-
import { LitElement as
|
|
4034
|
-
import { customElement as
|
|
4035
|
-
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 {
|
|
4036
4671
|
constructor() {
|
|
4037
4672
|
super(...arguments);
|
|
4038
4673
|
this.startPx = 0;
|
|
@@ -4041,11 +4676,11 @@ var DawSelectionElement = class extends LitElement10 {
|
|
|
4041
4676
|
render() {
|
|
4042
4677
|
const left = Math.min(this.startPx, this.endPx);
|
|
4043
4678
|
const width = Math.abs(this.endPx - this.startPx);
|
|
4044
|
-
if (width === 0) return
|
|
4045
|
-
return
|
|
4679
|
+
if (width === 0) return html10``;
|
|
4680
|
+
return html10`<div style="left: ${left}px; width: ${width}px;"></div>`;
|
|
4046
4681
|
}
|
|
4047
4682
|
};
|
|
4048
|
-
DawSelectionElement.styles =
|
|
4683
|
+
DawSelectionElement.styles = css10`
|
|
4049
4684
|
:host {
|
|
4050
4685
|
position: absolute;
|
|
4051
4686
|
top: 0;
|
|
@@ -4062,18 +4697,18 @@ DawSelectionElement.styles = css9`
|
|
|
4062
4697
|
}
|
|
4063
4698
|
`;
|
|
4064
4699
|
__decorateClass([
|
|
4065
|
-
|
|
4700
|
+
property9({ type: Number, attribute: false })
|
|
4066
4701
|
], DawSelectionElement.prototype, "startPx", 2);
|
|
4067
4702
|
__decorateClass([
|
|
4068
|
-
|
|
4703
|
+
property9({ type: Number, attribute: false })
|
|
4069
4704
|
], DawSelectionElement.prototype, "endPx", 2);
|
|
4070
4705
|
DawSelectionElement = __decorateClass([
|
|
4071
|
-
|
|
4706
|
+
customElement13("daw-selection")
|
|
4072
4707
|
], DawSelectionElement);
|
|
4073
4708
|
|
|
4074
4709
|
// src/elements/daw-record-button.ts
|
|
4075
|
-
import { html as
|
|
4076
|
-
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";
|
|
4077
4712
|
var DawRecordButtonElement = class extends DawTransportButton {
|
|
4078
4713
|
constructor() {
|
|
4079
4714
|
super(...arguments);
|
|
@@ -4114,7 +4749,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
4114
4749
|
}
|
|
4115
4750
|
}
|
|
4116
4751
|
render() {
|
|
4117
|
-
return
|
|
4752
|
+
return html11`
|
|
4118
4753
|
<button part="button" ?data-recording=${this._isRecording} @click=${this._onClick}>
|
|
4119
4754
|
<slot>Record</slot>
|
|
4120
4755
|
</button>
|
|
@@ -4134,7 +4769,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
4134
4769
|
};
|
|
4135
4770
|
DawRecordButtonElement.styles = [
|
|
4136
4771
|
DawTransportButton.styles,
|
|
4137
|
-
|
|
4772
|
+
css11`
|
|
4138
4773
|
button[data-recording] {
|
|
4139
4774
|
color: #d08070;
|
|
4140
4775
|
border-color: #d08070;
|
|
@@ -4146,14 +4781,14 @@ __decorateClass([
|
|
|
4146
4781
|
state4()
|
|
4147
4782
|
], DawRecordButtonElement.prototype, "_isRecording", 2);
|
|
4148
4783
|
DawRecordButtonElement = __decorateClass([
|
|
4149
|
-
|
|
4784
|
+
customElement14("daw-record-button")
|
|
4150
4785
|
], DawRecordButtonElement);
|
|
4151
4786
|
|
|
4152
4787
|
// src/elements/daw-keyboard-shortcuts.ts
|
|
4153
|
-
import { LitElement as
|
|
4154
|
-
import { customElement as
|
|
4788
|
+
import { LitElement as LitElement12 } from "lit";
|
|
4789
|
+
import { customElement as customElement15, property as property10 } from "lit/decorators.js";
|
|
4155
4790
|
import { handleKeyboardEvent } from "@waveform-playlist/core";
|
|
4156
|
-
var DawKeyboardShortcutsElement = class extends
|
|
4791
|
+
var DawKeyboardShortcutsElement = class extends LitElement12 {
|
|
4157
4792
|
constructor() {
|
|
4158
4793
|
super(...arguments);
|
|
4159
4794
|
this.playback = false;
|
|
@@ -4307,22 +4942,23 @@ var DawKeyboardShortcutsElement = class extends LitElement11 {
|
|
|
4307
4942
|
}
|
|
4308
4943
|
};
|
|
4309
4944
|
__decorateClass([
|
|
4310
|
-
|
|
4945
|
+
property10({ type: Boolean })
|
|
4311
4946
|
], DawKeyboardShortcutsElement.prototype, "playback", 2);
|
|
4312
4947
|
__decorateClass([
|
|
4313
|
-
|
|
4948
|
+
property10({ type: Boolean })
|
|
4314
4949
|
], DawKeyboardShortcutsElement.prototype, "splitting", 2);
|
|
4315
4950
|
__decorateClass([
|
|
4316
|
-
|
|
4951
|
+
property10({ type: Boolean })
|
|
4317
4952
|
], DawKeyboardShortcutsElement.prototype, "undo", 2);
|
|
4318
4953
|
DawKeyboardShortcutsElement = __decorateClass([
|
|
4319
|
-
|
|
4954
|
+
customElement15("daw-keyboard-shortcuts")
|
|
4320
4955
|
], DawKeyboardShortcutsElement);
|
|
4321
4956
|
export {
|
|
4322
4957
|
AudioResumeController,
|
|
4323
4958
|
ClipPointerHandler,
|
|
4324
4959
|
DawClipElement,
|
|
4325
4960
|
DawEditorElement,
|
|
4961
|
+
DawGridElement,
|
|
4326
4962
|
DawKeyboardShortcutsElement,
|
|
4327
4963
|
DawPauseButtonElement,
|
|
4328
4964
|
DawPlayButtonElement,
|