@dawcore/components 0.0.20 → 0.0.21
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 +1 -1
- package/dist/index.d.mts +30 -24
- package/dist/index.d.ts +30 -24
- package/dist/index.js +711 -470
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +699 -458
- package/dist/index.mjs.map +1 -1
- package/package.json +24 -15
package/dist/index.mjs
CHANGED
|
@@ -1196,8 +1196,8 @@ DawStopButtonElement = __decorateClass([
|
|
|
1196
1196
|
], DawStopButtonElement);
|
|
1197
1197
|
|
|
1198
1198
|
// src/elements/daw-editor.ts
|
|
1199
|
-
import { LitElement as
|
|
1200
|
-
import { customElement as
|
|
1199
|
+
import { LitElement as LitElement11, html as html10, css as css10 } from "lit";
|
|
1200
|
+
import { customElement as customElement13, property as property9, state as state3 } from "lit/decorators.js";
|
|
1201
1201
|
|
|
1202
1202
|
// src/types.ts
|
|
1203
1203
|
function isDomClip(desc) {
|
|
@@ -1681,10 +1681,268 @@ var PeakPipeline = class {
|
|
|
1681
1681
|
}
|
|
1682
1682
|
};
|
|
1683
1683
|
|
|
1684
|
-
// src/elements/daw-
|
|
1684
|
+
// src/elements/daw-ruler.ts
|
|
1685
1685
|
import { LitElement as LitElement8, html as html7, css as css6 } from "lit";
|
|
1686
1686
|
import { customElement as customElement10, property as property6 } from "lit/decorators.js";
|
|
1687
|
-
|
|
1687
|
+
|
|
1688
|
+
// src/utils/time-format.ts
|
|
1689
|
+
function formatTime(milliseconds) {
|
|
1690
|
+
const seconds = Math.floor(milliseconds / 1e3);
|
|
1691
|
+
const s = seconds % 60;
|
|
1692
|
+
const m = (seconds - s) / 60;
|
|
1693
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
// src/utils/smart-scale.ts
|
|
1697
|
+
var timeinfo = /* @__PURE__ */ new Map([
|
|
1698
|
+
[700, { marker: 1e3, bigStep: 500, smallStep: 100 }],
|
|
1699
|
+
[1500, { marker: 2e3, bigStep: 1e3, smallStep: 200 }],
|
|
1700
|
+
[2500, { marker: 2e3, bigStep: 1e3, smallStep: 500 }],
|
|
1701
|
+
[5e3, { marker: 5e3, bigStep: 1e3, smallStep: 500 }],
|
|
1702
|
+
[1e4, { marker: 1e4, bigStep: 5e3, smallStep: 1e3 }],
|
|
1703
|
+
[12e3, { marker: 15e3, bigStep: 5e3, smallStep: 1e3 }],
|
|
1704
|
+
[Infinity, { marker: 3e4, bigStep: 1e4, smallStep: 5e3 }]
|
|
1705
|
+
]);
|
|
1706
|
+
function getScaleInfo(samplesPerPixel) {
|
|
1707
|
+
for (const [resolution, config] of timeinfo) {
|
|
1708
|
+
if (samplesPerPixel < resolution) {
|
|
1709
|
+
return config;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return { marker: 3e4, bigStep: 1e4, smallStep: 5e3 };
|
|
1713
|
+
}
|
|
1714
|
+
function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight) {
|
|
1715
|
+
const widthX = Math.ceil(duration * sampleRate / samplesPerPixel);
|
|
1716
|
+
const config = getScaleInfo(samplesPerPixel);
|
|
1717
|
+
const { marker, bigStep, smallStep } = config;
|
|
1718
|
+
const canvasInfo = /* @__PURE__ */ new Map();
|
|
1719
|
+
const labels = [];
|
|
1720
|
+
const pixPerSec = sampleRate / samplesPerPixel;
|
|
1721
|
+
for (let counter = 0; ; counter += smallStep) {
|
|
1722
|
+
const pix = Math.floor(counter / 1e3 * pixPerSec);
|
|
1723
|
+
if (pix >= widthX) break;
|
|
1724
|
+
if (counter % marker === 0) {
|
|
1725
|
+
canvasInfo.set(pix, rulerHeight);
|
|
1726
|
+
labels.push({ pix, text: formatTime(counter) });
|
|
1727
|
+
} else if (counter % bigStep === 0) {
|
|
1728
|
+
canvasInfo.set(pix, Math.floor(rulerHeight / 2));
|
|
1729
|
+
} else if (counter % smallStep === 0) {
|
|
1730
|
+
canvasInfo.set(pix, Math.floor(rulerHeight / 5));
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
return { widthX, canvasInfo, labels };
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// src/utils/musical-tick-cache.ts
|
|
1737
|
+
import { computeMusicalTicks } from "@waveform-playlist/core";
|
|
1738
|
+
var cachedParams = null;
|
|
1739
|
+
var cachedResult = null;
|
|
1740
|
+
function meterEntriesMatch(a, b) {
|
|
1741
|
+
if (a.length !== b.length) return false;
|
|
1742
|
+
for (let i = 0; i < a.length; i++) {
|
|
1743
|
+
if (a[i].tick !== b[i].tick || a[i].numerator !== b[i].numerator || a[i].denominator !== b[i].denominator)
|
|
1744
|
+
return false;
|
|
1745
|
+
}
|
|
1746
|
+
return true;
|
|
1747
|
+
}
|
|
1748
|
+
function paramsMatch(a, b) {
|
|
1749
|
+
return a.ticksPerPixel === b.ticksPerPixel && a.startPixel === b.startPixel && a.endPixel === b.endPixel && meterEntriesMatch(a.meterEntries, b.meterEntries) && (a.ppqn ?? 960) === (b.ppqn ?? 960);
|
|
1750
|
+
}
|
|
1751
|
+
function getCachedMusicalTicks(params) {
|
|
1752
|
+
if (cachedParams && cachedResult && paramsMatch(cachedParams, params)) {
|
|
1753
|
+
return cachedResult;
|
|
1754
|
+
}
|
|
1755
|
+
cachedResult = computeMusicalTicks(params);
|
|
1756
|
+
cachedParams = {
|
|
1757
|
+
...params,
|
|
1758
|
+
meterEntries: params.meterEntries.map((e) => ({ ...e }))
|
|
1759
|
+
};
|
|
1760
|
+
return cachedResult;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// src/elements/daw-ruler.ts
|
|
1764
|
+
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
1765
|
+
var DawRulerElement = class extends LitElement8 {
|
|
1766
|
+
constructor() {
|
|
1767
|
+
super(...arguments);
|
|
1768
|
+
this.samplesPerPixel = 1024;
|
|
1769
|
+
this.sampleRate = 48e3;
|
|
1770
|
+
this.duration = 0;
|
|
1771
|
+
this.rulerHeight = 30;
|
|
1772
|
+
this.scaleMode = "temporal";
|
|
1773
|
+
this.ticksPerPixel = 4;
|
|
1774
|
+
this.meterEntries = [
|
|
1775
|
+
{ tick: 0, numerator: 4, denominator: 4 }
|
|
1776
|
+
];
|
|
1777
|
+
this.ppqn = 960;
|
|
1778
|
+
this.totalWidth = 0;
|
|
1779
|
+
this._tickData = null;
|
|
1780
|
+
this._musicalTickData = null;
|
|
1781
|
+
}
|
|
1782
|
+
willUpdate() {
|
|
1783
|
+
if (this.scaleMode === "beats" && this.totalWidth > 0) {
|
|
1784
|
+
this._musicalTickData = getCachedMusicalTicks({
|
|
1785
|
+
meterEntries: this.meterEntries,
|
|
1786
|
+
ticksPerPixel: this.ticksPerPixel,
|
|
1787
|
+
startPixel: 0,
|
|
1788
|
+
endPixel: this.totalWidth,
|
|
1789
|
+
ppqn: this.ppqn
|
|
1790
|
+
});
|
|
1791
|
+
this._tickData = null;
|
|
1792
|
+
} else if (this.duration > 0 || this.totalWidth > 0) {
|
|
1793
|
+
const widthDerivedDuration = this.totalWidth * this.samplesPerPixel / this.sampleRate;
|
|
1794
|
+
const effectiveDuration = Math.max(this.duration, widthDerivedDuration);
|
|
1795
|
+
this._musicalTickData = null;
|
|
1796
|
+
this._tickData = computeTemporalTicks(
|
|
1797
|
+
this.samplesPerPixel,
|
|
1798
|
+
this.sampleRate,
|
|
1799
|
+
effectiveDuration,
|
|
1800
|
+
this.rulerHeight
|
|
1801
|
+
);
|
|
1802
|
+
} else {
|
|
1803
|
+
this._musicalTickData = null;
|
|
1804
|
+
this._tickData = null;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
render() {
|
|
1808
|
+
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
1809
|
+
if (widthX <= 0) return html7``;
|
|
1810
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH3);
|
|
1811
|
+
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
1812
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1813
|
+
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
1814
|
+
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
1815
|
+
return html7`
|
|
1816
|
+
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
1817
|
+
${indices.map((i) => {
|
|
1818
|
+
const width = Math.min(MAX_CANVAS_WIDTH3, widthX - i * MAX_CANVAS_WIDTH3);
|
|
1819
|
+
return html7`
|
|
1820
|
+
<canvas
|
|
1821
|
+
data-index=${i}
|
|
1822
|
+
width=${width * dpr}
|
|
1823
|
+
height=${this.rulerHeight * dpr}
|
|
1824
|
+
style="left: ${i * MAX_CANVAS_WIDTH3}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
1825
|
+
></canvas>
|
|
1826
|
+
`;
|
|
1827
|
+
})}
|
|
1828
|
+
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
1829
|
+
(t) => html7`<span
|
|
1830
|
+
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
1831
|
+
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
1832
|
+
>${t.label}</span
|
|
1833
|
+
>`
|
|
1834
|
+
) : temporalLabels.map(
|
|
1835
|
+
({ pix, text }) => html7`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
1836
|
+
)}
|
|
1837
|
+
</div>
|
|
1838
|
+
`;
|
|
1839
|
+
}
|
|
1840
|
+
updated() {
|
|
1841
|
+
this._drawTicks();
|
|
1842
|
+
}
|
|
1843
|
+
_drawTicks() {
|
|
1844
|
+
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
1845
|
+
if (!canvases) return;
|
|
1846
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1847
|
+
const rulerColor = getComputedStyle(this).getPropertyValue("--daw-ruler-color").trim() || "#c49a6c";
|
|
1848
|
+
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
1849
|
+
for (const canvas of canvases) {
|
|
1850
|
+
const idx = Number(canvas.dataset.index);
|
|
1851
|
+
const ctx = canvas.getContext("2d");
|
|
1852
|
+
if (!ctx) continue;
|
|
1853
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH3, widthX - idx * MAX_CANVAS_WIDTH3);
|
|
1854
|
+
const globalOffset = idx * MAX_CANVAS_WIDTH3;
|
|
1855
|
+
ctx.resetTransform();
|
|
1856
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1857
|
+
ctx.scale(dpr, dpr);
|
|
1858
|
+
ctx.strokeStyle = rulerColor;
|
|
1859
|
+
ctx.lineWidth = 1;
|
|
1860
|
+
if (this.scaleMode === "beats" && this._musicalTickData) {
|
|
1861
|
+
const h = this.rulerHeight;
|
|
1862
|
+
for (const tick of this._musicalTickData.ticks) {
|
|
1863
|
+
const localX = tick.pixel - globalOffset;
|
|
1864
|
+
if (localX < 0 || localX >= canvasWidth) continue;
|
|
1865
|
+
const tickH = tick.type === "major" ? h * 0.6 : tick.type === "minor" ? h * 0.35 : h * 0.15;
|
|
1866
|
+
ctx.globalAlpha = tick.type === "major" ? 1 : 0.5;
|
|
1867
|
+
ctx.beginPath();
|
|
1868
|
+
ctx.moveTo(localX + 0.5, h);
|
|
1869
|
+
ctx.lineTo(localX + 0.5, h - tickH);
|
|
1870
|
+
ctx.stroke();
|
|
1871
|
+
}
|
|
1872
|
+
ctx.globalAlpha = 1;
|
|
1873
|
+
} else if (this._tickData) {
|
|
1874
|
+
for (const [pix, height] of this._tickData.canvasInfo) {
|
|
1875
|
+
const localX = pix - globalOffset;
|
|
1876
|
+
if (localX < 0 || localX >= canvasWidth) continue;
|
|
1877
|
+
ctx.beginPath();
|
|
1878
|
+
ctx.moveTo(localX + 0.5, this.rulerHeight);
|
|
1879
|
+
ctx.lineTo(localX + 0.5, this.rulerHeight - height);
|
|
1880
|
+
ctx.stroke();
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
};
|
|
1886
|
+
DawRulerElement.styles = css6`
|
|
1887
|
+
:host {
|
|
1888
|
+
display: block;
|
|
1889
|
+
position: relative;
|
|
1890
|
+
background: var(--daw-ruler-background, #0f0f1a);
|
|
1891
|
+
}
|
|
1892
|
+
.container {
|
|
1893
|
+
position: relative;
|
|
1894
|
+
}
|
|
1895
|
+
canvas {
|
|
1896
|
+
position: absolute;
|
|
1897
|
+
top: 0;
|
|
1898
|
+
}
|
|
1899
|
+
.label {
|
|
1900
|
+
position: absolute;
|
|
1901
|
+
font-size: 0.7rem;
|
|
1902
|
+
line-height: 1;
|
|
1903
|
+
white-space: nowrap;
|
|
1904
|
+
color: var(--daw-ruler-color, #c49a6c);
|
|
1905
|
+
top: 1px;
|
|
1906
|
+
}
|
|
1907
|
+
.label.centered {
|
|
1908
|
+
transform: translateX(-50%);
|
|
1909
|
+
}
|
|
1910
|
+
`;
|
|
1911
|
+
__decorateClass([
|
|
1912
|
+
property6({ type: Number, attribute: false })
|
|
1913
|
+
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
1914
|
+
__decorateClass([
|
|
1915
|
+
property6({ type: Number, attribute: false })
|
|
1916
|
+
], DawRulerElement.prototype, "sampleRate", 2);
|
|
1917
|
+
__decorateClass([
|
|
1918
|
+
property6({ type: Number, attribute: false })
|
|
1919
|
+
], DawRulerElement.prototype, "duration", 2);
|
|
1920
|
+
__decorateClass([
|
|
1921
|
+
property6({ type: Number, attribute: false })
|
|
1922
|
+
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
1923
|
+
__decorateClass([
|
|
1924
|
+
property6({ type: String, attribute: false })
|
|
1925
|
+
], DawRulerElement.prototype, "scaleMode", 2);
|
|
1926
|
+
__decorateClass([
|
|
1927
|
+
property6({ type: Number, attribute: false })
|
|
1928
|
+
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
1929
|
+
__decorateClass([
|
|
1930
|
+
property6({ attribute: false })
|
|
1931
|
+
], DawRulerElement.prototype, "meterEntries", 2);
|
|
1932
|
+
__decorateClass([
|
|
1933
|
+
property6({ type: Number, attribute: false })
|
|
1934
|
+
], DawRulerElement.prototype, "ppqn", 2);
|
|
1935
|
+
__decorateClass([
|
|
1936
|
+
property6({ type: Number, attribute: false })
|
|
1937
|
+
], DawRulerElement.prototype, "totalWidth", 2);
|
|
1938
|
+
DawRulerElement = __decorateClass([
|
|
1939
|
+
customElement10("daw-ruler")
|
|
1940
|
+
], DawRulerElement);
|
|
1941
|
+
|
|
1942
|
+
// src/elements/daw-track-controls.ts
|
|
1943
|
+
import { LitElement as LitElement9, html as html8, css as css7 } from "lit";
|
|
1944
|
+
import { customElement as customElement11, property as property7 } from "lit/decorators.js";
|
|
1945
|
+
var DawTrackControlsElement = class extends LitElement9 {
|
|
1688
1946
|
constructor() {
|
|
1689
1947
|
super(...arguments);
|
|
1690
1948
|
this.trackId = null;
|
|
@@ -1718,6 +1976,17 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1718
1976
|
);
|
|
1719
1977
|
};
|
|
1720
1978
|
}
|
|
1979
|
+
firstUpdated() {
|
|
1980
|
+
requestAnimationFrame(() => {
|
|
1981
|
+
if (!this.isConnected) return;
|
|
1982
|
+
const rect = this.getBoundingClientRect();
|
|
1983
|
+
if (rect.width > 0 && rect.height === 0) {
|
|
1984
|
+
console.warn(
|
|
1985
|
+
"[dawcore] <daw-track-controls> has zero height: container-type: size requires an explicit height on the element (the editor sets one automatically; standalone usage must too). The controls are currently invisible."
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1721
1990
|
_dispatchControl(prop, value) {
|
|
1722
1991
|
if (!this.trackId) return;
|
|
1723
1992
|
this.dispatchEvent(
|
|
@@ -1732,7 +2001,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1732
2001
|
const volPercent = Math.round(this.volume * 100);
|
|
1733
2002
|
const panPercent = Math.round(Math.abs(this.pan) * 100);
|
|
1734
2003
|
const panDisplay = this.pan === 0 ? "C" : (this.pan > 0 ? "R" : "L") + panPercent;
|
|
1735
|
-
return
|
|
2004
|
+
return html8`
|
|
1736
2005
|
<div class="header">
|
|
1737
2006
|
<span class="name" title=${this.trackName}>${this.trackName || "Untitled"}</span>
|
|
1738
2007
|
<button class="remove-btn" @click=${this._onRemoveClick} title="Remove track">
|
|
@@ -1751,7 +2020,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1751
2020
|
S
|
|
1752
2021
|
</button>
|
|
1753
2022
|
</div>
|
|
1754
|
-
<div class="slider-row">
|
|
2023
|
+
<div class="slider-row vol-row">
|
|
1755
2024
|
<span class="slider-label">
|
|
1756
2025
|
<span class="slider-label-name">Vol</span>
|
|
1757
2026
|
<span class="slider-label-value">${volPercent}%</span>
|
|
@@ -1765,7 +2034,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1765
2034
|
@input=${this._onVolumeInput}
|
|
1766
2035
|
/>
|
|
1767
2036
|
</div>
|
|
1768
|
-
<div class="slider-row">
|
|
2037
|
+
<div class="slider-row pan-row">
|
|
1769
2038
|
<span class="slider-label">
|
|
1770
2039
|
<span class="slider-label-name">Pan</span>
|
|
1771
2040
|
<span class="slider-label-value">${panDisplay}</span>
|
|
@@ -1782,7 +2051,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1782
2051
|
`;
|
|
1783
2052
|
}
|
|
1784
2053
|
};
|
|
1785
|
-
DawTrackControlsElement.styles =
|
|
2054
|
+
DawTrackControlsElement.styles = css7`
|
|
1786
2055
|
:host {
|
|
1787
2056
|
display: flex;
|
|
1788
2057
|
flex-direction: column;
|
|
@@ -1795,6 +2064,7 @@ DawTrackControlsElement.styles = css6`
|
|
|
1795
2064
|
font-family: system-ui, sans-serif;
|
|
1796
2065
|
font-size: 11px;
|
|
1797
2066
|
overflow: hidden;
|
|
2067
|
+
container-type: size;
|
|
1798
2068
|
}
|
|
1799
2069
|
.header {
|
|
1800
2070
|
display: flex;
|
|
@@ -1914,64 +2184,52 @@ DawTrackControlsElement.styles = css6`
|
|
|
1914
2184
|
border: none;
|
|
1915
2185
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
|
1916
2186
|
}
|
|
2187
|
+
/* Compact modes: drop sliders when the row is too short for the full
|
|
2188
|
+
stack. Thresholds are CONTENT-BOX heights — the host is border-box
|
|
2189
|
+
with 12px vertical padding + 1px border, so an editor-given height H
|
|
2190
|
+
enters compact mode at H <= 89px (Pan hidden) and H <= 73px (Vol also
|
|
2191
|
+
hidden). NOTE: container-type: size requires an explicit height on
|
|
2192
|
+
the host — the editor always provides one; standalone consumers must
|
|
2193
|
+
too (see the firstUpdated guard). */
|
|
2194
|
+
@container (max-height: 76px) {
|
|
2195
|
+
.pan-row {
|
|
2196
|
+
display: none;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
@container (max-height: 60px) {
|
|
2200
|
+
.vol-row {
|
|
2201
|
+
display: none;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
1917
2204
|
`;
|
|
1918
2205
|
__decorateClass([
|
|
1919
|
-
|
|
2206
|
+
property7({ attribute: false })
|
|
1920
2207
|
], DawTrackControlsElement.prototype, "trackId", 2);
|
|
1921
2208
|
__decorateClass([
|
|
1922
|
-
|
|
2209
|
+
property7({ attribute: false })
|
|
1923
2210
|
], DawTrackControlsElement.prototype, "trackName", 2);
|
|
1924
2211
|
__decorateClass([
|
|
1925
|
-
|
|
2212
|
+
property7({ type: Number, attribute: false })
|
|
1926
2213
|
], DawTrackControlsElement.prototype, "volume", 2);
|
|
1927
2214
|
__decorateClass([
|
|
1928
|
-
|
|
2215
|
+
property7({ type: Number, attribute: false })
|
|
1929
2216
|
], DawTrackControlsElement.prototype, "pan", 2);
|
|
1930
2217
|
__decorateClass([
|
|
1931
|
-
|
|
2218
|
+
property7({ type: Boolean, attribute: false })
|
|
1932
2219
|
], DawTrackControlsElement.prototype, "muted", 2);
|
|
1933
2220
|
__decorateClass([
|
|
1934
|
-
|
|
2221
|
+
property7({ type: Boolean, attribute: false })
|
|
1935
2222
|
], DawTrackControlsElement.prototype, "soloed", 2);
|
|
1936
2223
|
DawTrackControlsElement = __decorateClass([
|
|
1937
|
-
|
|
2224
|
+
customElement11("daw-track-controls")
|
|
1938
2225
|
], DawTrackControlsElement);
|
|
1939
2226
|
|
|
1940
2227
|
// src/elements/daw-grid.ts
|
|
1941
|
-
import { LitElement as
|
|
1942
|
-
import { customElement as
|
|
2228
|
+
import { LitElement as LitElement10, html as html9, css as css8 } from "lit";
|
|
2229
|
+
import { customElement as customElement12, property as property8 } from "lit/decorators.js";
|
|
1943
2230
|
import { MIN_PIXELS_PER_UNIT } from "@waveform-playlist/core";
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
import { computeMusicalTicks } from "@waveform-playlist/core";
|
|
1947
|
-
var cachedParams = null;
|
|
1948
|
-
var cachedResult = null;
|
|
1949
|
-
function meterEntriesMatch(a, b) {
|
|
1950
|
-
if (a.length !== b.length) return false;
|
|
1951
|
-
for (let i = 0; i < a.length; i++) {
|
|
1952
|
-
if (a[i].tick !== b[i].tick || a[i].numerator !== b[i].numerator || a[i].denominator !== b[i].denominator)
|
|
1953
|
-
return false;
|
|
1954
|
-
}
|
|
1955
|
-
return true;
|
|
1956
|
-
}
|
|
1957
|
-
function paramsMatch(a, b) {
|
|
1958
|
-
return a.ticksPerPixel === b.ticksPerPixel && a.startPixel === b.startPixel && a.endPixel === b.endPixel && meterEntriesMatch(a.meterEntries, b.meterEntries) && (a.ppqn ?? 960) === (b.ppqn ?? 960);
|
|
1959
|
-
}
|
|
1960
|
-
function getCachedMusicalTicks(params) {
|
|
1961
|
-
if (cachedParams && cachedResult && paramsMatch(cachedParams, params)) {
|
|
1962
|
-
return cachedResult;
|
|
1963
|
-
}
|
|
1964
|
-
cachedResult = computeMusicalTicks(params);
|
|
1965
|
-
cachedParams = {
|
|
1966
|
-
...params,
|
|
1967
|
-
meterEntries: params.meterEntries.map((e) => ({ ...e }))
|
|
1968
|
-
};
|
|
1969
|
-
return cachedResult;
|
|
1970
|
-
}
|
|
1971
|
-
|
|
1972
|
-
// src/elements/daw-grid.ts
|
|
1973
|
-
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
1974
|
-
var DawGridElement = class extends LitElement9 {
|
|
2231
|
+
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
2232
|
+
var DawGridElement = class extends LitElement10 {
|
|
1975
2233
|
constructor() {
|
|
1976
2234
|
super(...arguments);
|
|
1977
2235
|
this.ticksPerPixel = 24;
|
|
@@ -1999,25 +2257,25 @@ var DawGridElement = class extends LitElement9 {
|
|
|
1999
2257
|
}
|
|
2000
2258
|
}
|
|
2001
2259
|
render() {
|
|
2002
|
-
if (!this._tickData) return
|
|
2260
|
+
if (!this._tickData) return html9``;
|
|
2003
2261
|
const totalWidth = this.length;
|
|
2004
2262
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
2005
2263
|
const indices = getVisibleChunkIndices(
|
|
2006
2264
|
totalWidth,
|
|
2007
|
-
|
|
2265
|
+
MAX_CANVAS_WIDTH4,
|
|
2008
2266
|
this.visibleStart,
|
|
2009
2267
|
this.visibleEnd
|
|
2010
2268
|
);
|
|
2011
|
-
return
|
|
2269
|
+
return html9`
|
|
2012
2270
|
<div class="container" style="width: ${totalWidth}px; height: ${this.height}px;">
|
|
2013
2271
|
${indices.map((i) => {
|
|
2014
|
-
const width = Math.min(
|
|
2015
|
-
return
|
|
2272
|
+
const width = Math.min(MAX_CANVAS_WIDTH4, totalWidth - i * MAX_CANVAS_WIDTH4);
|
|
2273
|
+
return html9`
|
|
2016
2274
|
<canvas
|
|
2017
2275
|
data-index=${i}
|
|
2018
2276
|
width=${width * dpr}
|
|
2019
2277
|
height=${this.height * dpr}
|
|
2020
|
-
style="left: ${i *
|
|
2278
|
+
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.height}px;"
|
|
2021
2279
|
></canvas>
|
|
2022
2280
|
`;
|
|
2023
2281
|
})}
|
|
@@ -2041,8 +2299,8 @@ var DawGridElement = class extends LitElement9 {
|
|
|
2041
2299
|
const idx = Number(canvas.dataset.index);
|
|
2042
2300
|
const ctx = canvas.getContext("2d");
|
|
2043
2301
|
if (!ctx) continue;
|
|
2044
|
-
const chunkLeft = idx *
|
|
2045
|
-
const canvasWidth = Math.min(
|
|
2302
|
+
const chunkLeft = idx * MAX_CANVAS_WIDTH4;
|
|
2303
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, this.length - chunkLeft);
|
|
2046
2304
|
ctx.resetTransform();
|
|
2047
2305
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2048
2306
|
ctx.scale(dpr, dpr);
|
|
@@ -2073,7 +2331,7 @@ var DawGridElement = class extends LitElement9 {
|
|
|
2073
2331
|
}
|
|
2074
2332
|
}
|
|
2075
2333
|
};
|
|
2076
|
-
DawGridElement.styles =
|
|
2334
|
+
DawGridElement.styles = css8`
|
|
2077
2335
|
:host {
|
|
2078
2336
|
display: block;
|
|
2079
2337
|
position: absolute;
|
|
@@ -2091,33 +2349,33 @@ DawGridElement.styles = css7`
|
|
|
2091
2349
|
}
|
|
2092
2350
|
`;
|
|
2093
2351
|
__decorateClass([
|
|
2094
|
-
|
|
2352
|
+
property8({ type: Number, attribute: false })
|
|
2095
2353
|
], DawGridElement.prototype, "ticksPerPixel", 2);
|
|
2096
2354
|
__decorateClass([
|
|
2097
|
-
|
|
2355
|
+
property8({ attribute: false })
|
|
2098
2356
|
], DawGridElement.prototype, "meterEntries", 2);
|
|
2099
2357
|
__decorateClass([
|
|
2100
|
-
|
|
2358
|
+
property8({ type: Number, attribute: false })
|
|
2101
2359
|
], DawGridElement.prototype, "ppqn", 2);
|
|
2102
2360
|
__decorateClass([
|
|
2103
|
-
|
|
2361
|
+
property8({ type: Number, attribute: false })
|
|
2104
2362
|
], DawGridElement.prototype, "visibleStart", 2);
|
|
2105
2363
|
__decorateClass([
|
|
2106
|
-
|
|
2364
|
+
property8({ type: Number, attribute: false })
|
|
2107
2365
|
], DawGridElement.prototype, "visibleEnd", 2);
|
|
2108
2366
|
__decorateClass([
|
|
2109
|
-
|
|
2367
|
+
property8({ type: Number, attribute: false })
|
|
2110
2368
|
], DawGridElement.prototype, "length", 2);
|
|
2111
2369
|
__decorateClass([
|
|
2112
|
-
|
|
2370
|
+
property8({ type: Number, attribute: false })
|
|
2113
2371
|
], DawGridElement.prototype, "height", 2);
|
|
2114
2372
|
DawGridElement = __decorateClass([
|
|
2115
|
-
|
|
2373
|
+
customElement12("daw-grid")
|
|
2116
2374
|
], DawGridElement);
|
|
2117
2375
|
|
|
2118
2376
|
// src/styles/theme.ts
|
|
2119
|
-
import { css as
|
|
2120
|
-
var hostStyles =
|
|
2377
|
+
import { css as css9 } from "lit";
|
|
2378
|
+
var hostStyles = css9`
|
|
2121
2379
|
:host {
|
|
2122
2380
|
--daw-wave-color: #c49a6c;
|
|
2123
2381
|
--daw-progress-color: #63c75f;
|
|
@@ -2133,7 +2391,7 @@ var hostStyles = css8`
|
|
|
2133
2391
|
--daw-clip-header-text: #e0d4c8;
|
|
2134
2392
|
}
|
|
2135
2393
|
`;
|
|
2136
|
-
var clipStyles =
|
|
2394
|
+
var clipStyles = css9`
|
|
2137
2395
|
.clip-container {
|
|
2138
2396
|
position: absolute;
|
|
2139
2397
|
overflow: hidden;
|
|
@@ -2885,7 +3143,11 @@ var PointerHandler = class {
|
|
|
2885
3143
|
e.preventDefault();
|
|
2886
3144
|
this._timeline = this._host.shadowRoot?.querySelector(".timeline");
|
|
2887
3145
|
if (this._timeline) {
|
|
2888
|
-
|
|
3146
|
+
try {
|
|
3147
|
+
this._timeline.setPointerCapture(e.pointerId);
|
|
3148
|
+
} catch (err) {
|
|
3149
|
+
console.warn("[dawcore] setPointerCapture failed: " + String(err));
|
|
3150
|
+
}
|
|
2889
3151
|
const onMove = (me) => clipHandler.onPointerMove(me);
|
|
2890
3152
|
const onUp = (ue) => {
|
|
2891
3153
|
clipHandler.onPointerUp(ue);
|
|
@@ -2907,11 +3169,20 @@ var PointerHandler = class {
|
|
|
2907
3169
|
}
|
|
2908
3170
|
}
|
|
2909
3171
|
this._timeline = this._host.shadowRoot?.querySelector(".timeline");
|
|
2910
|
-
if (!this._timeline)
|
|
3172
|
+
if (!this._timeline) {
|
|
3173
|
+
console.warn(
|
|
3174
|
+
"[dawcore] PointerHandler: .timeline not found in shadow root \u2014 seek/selection ignored"
|
|
3175
|
+
);
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
2911
3178
|
this._timelineRect = this._timeline.getBoundingClientRect();
|
|
2912
3179
|
this._dragStartPx = this._pxFromPointer(e);
|
|
2913
3180
|
this._isDragging = false;
|
|
2914
|
-
|
|
3181
|
+
try {
|
|
3182
|
+
this._timeline.setPointerCapture(e.pointerId);
|
|
3183
|
+
} catch (err) {
|
|
3184
|
+
console.warn("[dawcore] setPointerCapture failed: " + String(err));
|
|
3185
|
+
}
|
|
2915
3186
|
this._timeline.addEventListener("pointermove", this._onPointerMove);
|
|
2916
3187
|
this._timeline.addEventListener("pointerup", this._onPointerUp);
|
|
2917
3188
|
};
|
|
@@ -3843,9 +4114,143 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
3843
4114
|
}
|
|
3844
4115
|
}
|
|
3845
4116
|
|
|
4117
|
+
// src/controllers/scroll-sync-controller.ts
|
|
4118
|
+
var LINE_HEIGHT_PX = 16;
|
|
4119
|
+
var ScrollSyncController = class {
|
|
4120
|
+
constructor(host) {
|
|
4121
|
+
this._scrollContainer = null;
|
|
4122
|
+
this._wheelTargets = /* @__PURE__ */ new Set();
|
|
4123
|
+
this._warnedX = false;
|
|
4124
|
+
this._warnedY = false;
|
|
4125
|
+
/** Selector (in host shadow DOM) for the scroll container. */
|
|
4126
|
+
this.scrollSelector = "";
|
|
4127
|
+
/** Selector for the element receiving translate3d(-scrollLeft, 0, 0). */
|
|
4128
|
+
this.xTargetSelector = "";
|
|
4129
|
+
/** Selector for the element receiving translate3d(0, -scrollTop, 0). */
|
|
4130
|
+
this.yTargetSelector = "";
|
|
4131
|
+
/**
|
|
4132
|
+
* Selector (or comma-separated selectors) for elements whose wheel events
|
|
4133
|
+
* forward to the scroll container. All matching elements receive listeners.
|
|
4134
|
+
*/
|
|
4135
|
+
this.wheelForwardSelector = "";
|
|
4136
|
+
this._onScroll = () => {
|
|
4137
|
+
this._apply();
|
|
4138
|
+
};
|
|
4139
|
+
this._onWheel = (e) => {
|
|
4140
|
+
const sc = this._scrollContainer;
|
|
4141
|
+
if (!sc) return;
|
|
4142
|
+
const scale = e.deltaMode === WheelEvent.DOM_DELTA_LINE ? LINE_HEIGHT_PX : e.deltaMode === WheelEvent.DOM_DELTA_PAGE ? sc.clientHeight : 1;
|
|
4143
|
+
const scaleX = e.deltaMode === WheelEvent.DOM_DELTA_PAGE ? sc.clientWidth : scale;
|
|
4144
|
+
const beforeLeft = sc.scrollLeft;
|
|
4145
|
+
const beforeTop = sc.scrollTop;
|
|
4146
|
+
sc.scrollLeft += e.deltaX * scaleX;
|
|
4147
|
+
sc.scrollTop += e.deltaY * scale;
|
|
4148
|
+
if (sc.scrollLeft !== beforeLeft || sc.scrollTop !== beforeTop) {
|
|
4149
|
+
e.preventDefault();
|
|
4150
|
+
}
|
|
4151
|
+
};
|
|
4152
|
+
this._host = host;
|
|
4153
|
+
host.addController(this);
|
|
4154
|
+
}
|
|
4155
|
+
hostConnected() {
|
|
4156
|
+
requestAnimationFrame(() => {
|
|
4157
|
+
if (!this._host.isConnected) return;
|
|
4158
|
+
this._attach();
|
|
4159
|
+
if (!this._scrollContainer && this.scrollSelector) {
|
|
4160
|
+
console.warn(
|
|
4161
|
+
'[dawcore] ScrollSyncController: scroll container not found for "' + this.scrollSelector + '"'
|
|
4162
|
+
);
|
|
4163
|
+
}
|
|
4164
|
+
});
|
|
4165
|
+
}
|
|
4166
|
+
hostDisconnected() {
|
|
4167
|
+
this._scrollContainer?.removeEventListener("scroll", this._onScroll);
|
|
4168
|
+
this._scrollContainer = null;
|
|
4169
|
+
for (const target of this._wheelTargets) {
|
|
4170
|
+
target.removeEventListener("wheel", this._onWheel);
|
|
4171
|
+
}
|
|
4172
|
+
this._wheelTargets.clear();
|
|
4173
|
+
}
|
|
4174
|
+
/**
|
|
4175
|
+
* Re-attach and re-apply transforms from the current scroll position.
|
|
4176
|
+
* Called from the host's updated() so elements created by a re-render
|
|
4177
|
+
* (e.g. the ruler appearing when the first track loads) pick up the
|
|
4178
|
+
* current offset and listeners.
|
|
4179
|
+
*/
|
|
4180
|
+
sync() {
|
|
4181
|
+
this._attach();
|
|
4182
|
+
}
|
|
4183
|
+
_query(selector) {
|
|
4184
|
+
return selector ? this._host.shadowRoot?.querySelector(selector) : null;
|
|
4185
|
+
}
|
|
4186
|
+
_queryAll(selector) {
|
|
4187
|
+
if (!selector) return [];
|
|
4188
|
+
return Array.from(this._host.shadowRoot?.querySelectorAll(selector) ?? []);
|
|
4189
|
+
}
|
|
4190
|
+
_attach() {
|
|
4191
|
+
const container = this._query(this.scrollSelector);
|
|
4192
|
+
if (!container) {
|
|
4193
|
+
if (this._scrollContainer && !this._scrollContainer.isConnected) {
|
|
4194
|
+
console.warn(
|
|
4195
|
+
'[dawcore] ScrollSyncController: scroll container "' + this.scrollSelector + '" was removed from the DOM \u2014 detaching listeners until it reappears.'
|
|
4196
|
+
);
|
|
4197
|
+
this._scrollContainer.removeEventListener("scroll", this._onScroll);
|
|
4198
|
+
this._scrollContainer = null;
|
|
4199
|
+
for (const t of this._wheelTargets) t.removeEventListener("wheel", this._onWheel);
|
|
4200
|
+
this._wheelTargets.clear();
|
|
4201
|
+
}
|
|
4202
|
+
return;
|
|
4203
|
+
}
|
|
4204
|
+
if (container !== this._scrollContainer) {
|
|
4205
|
+
this._scrollContainer?.removeEventListener("scroll", this._onScroll);
|
|
4206
|
+
this._scrollContainer = container;
|
|
4207
|
+
container.addEventListener("scroll", this._onScroll, { passive: true });
|
|
4208
|
+
}
|
|
4209
|
+
const nextTargets = new Set(this._queryAll(this.wheelForwardSelector));
|
|
4210
|
+
for (const old of this._wheelTargets) {
|
|
4211
|
+
if (!nextTargets.has(old)) {
|
|
4212
|
+
old.removeEventListener("wheel", this._onWheel);
|
|
4213
|
+
this._wheelTargets.delete(old);
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
for (const next of nextTargets) {
|
|
4217
|
+
if (!this._wheelTargets.has(next)) {
|
|
4218
|
+
next.addEventListener("wheel", this._onWheel, { passive: false });
|
|
4219
|
+
this._wheelTargets.add(next);
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
this._apply();
|
|
4223
|
+
}
|
|
4224
|
+
_apply() {
|
|
4225
|
+
const sc = this._scrollContainer;
|
|
4226
|
+
if (!sc) return;
|
|
4227
|
+
const xTarget = this._query(this.xTargetSelector);
|
|
4228
|
+
if (xTarget) {
|
|
4229
|
+
xTarget.style.transform = `translate3d(${-sc.scrollLeft}px, 0, 0)`;
|
|
4230
|
+
this._warnedX = false;
|
|
4231
|
+
} else if (this.xTargetSelector && sc.scrollLeft !== 0 && !this._warnedX) {
|
|
4232
|
+
this._warnedX = true;
|
|
4233
|
+
console.warn(
|
|
4234
|
+
'[dawcore] ScrollSyncController: x target "' + this.xTargetSelector + '" not found while scrolled \u2014 the synced pane will appear frozen. Check the selector, or clear it if the target is intentionally not rendered.'
|
|
4235
|
+
);
|
|
4236
|
+
}
|
|
4237
|
+
const yTarget = this._query(this.yTargetSelector);
|
|
4238
|
+
if (yTarget) {
|
|
4239
|
+
yTarget.style.transform = `translate3d(0, ${-sc.scrollTop}px, 0)`;
|
|
4240
|
+
this._warnedY = false;
|
|
4241
|
+
} else if (this.yTargetSelector && sc.scrollTop !== 0 && !this._warnedY) {
|
|
4242
|
+
this._warnedY = true;
|
|
4243
|
+
console.warn(
|
|
4244
|
+
'[dawcore] ScrollSyncController: y target "' + this.yTargetSelector + '" not found while scrolled \u2014 the synced pane will appear frozen. Check the selector, or clear it if the target is intentionally not rendered.'
|
|
4245
|
+
);
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
};
|
|
4249
|
+
|
|
3846
4250
|
// src/elements/daw-editor.ts
|
|
4251
|
+
var RULER_HEIGHT = 30;
|
|
3847
4252
|
var NO_ADAPTER_ERROR = "No PlayoutAdapter set on <daw-editor>. Set editor.adapter before use.\n\n // Option 1: Native Web Audio (no Tone.js)\n npm install @dawcore/transport\n import { NativePlayoutAdapter } from '@dawcore/transport';\n editor.adapter = new NativePlayoutAdapter(new AudioContext());\n\n // Option 2: Tone.js (effects, MIDI synths)\n npm install @waveform-playlist/playout\n import { createToneAdapter } from '@waveform-playlist/playout';\n editor.adapter = createToneAdapter();";
|
|
3848
|
-
var DawEditorElement = class extends
|
|
4253
|
+
var DawEditorElement = class extends LitElement11 {
|
|
3849
4254
|
constructor() {
|
|
3850
4255
|
super(...arguments);
|
|
3851
4256
|
this._samplesPerPixel = 1024;
|
|
@@ -3904,6 +4309,11 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
3904
4309
|
v.scrollSelector = ".scroll-area";
|
|
3905
4310
|
return v;
|
|
3906
4311
|
})();
|
|
4312
|
+
this._scrollSync = (() => {
|
|
4313
|
+
const s = new ScrollSyncController(this);
|
|
4314
|
+
s.scrollSelector = ".scroll-area";
|
|
4315
|
+
return s;
|
|
4316
|
+
})();
|
|
3907
4317
|
/**
|
|
3908
4318
|
* Cache of the last ViewportState forwarded to the spectrogram controller.
|
|
3909
4319
|
* Lit's `updated()` fires on every reactive state change (`_isPlaying`,
|
|
@@ -4450,6 +4860,13 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
4450
4860
|
}
|
|
4451
4861
|
}
|
|
4452
4862
|
updated(_changed) {
|
|
4863
|
+
this._scrollSync.xTargetSelector = this._showRuler ? ".ruler-content" : "";
|
|
4864
|
+
this._scrollSync.yTargetSelector = this._showControls ? ".controls-column" : "";
|
|
4865
|
+
this._scrollSync.wheelForwardSelector = [
|
|
4866
|
+
this._showControls ? ".controls-viewport" : "",
|
|
4867
|
+
this._showRuler ? ".ruler-viewport" : ""
|
|
4868
|
+
].filter(Boolean).join(", ");
|
|
4869
|
+
this._scrollSync.sync();
|
|
4453
4870
|
if (this._spectrogramController) {
|
|
4454
4871
|
const vs = this._viewport.visibleStart;
|
|
4455
4872
|
const ve = this._viewport.visibleEnd;
|
|
@@ -5611,7 +6028,7 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5611
6028
|
const w = Math.floor(audibleSamples / renderSpp);
|
|
5612
6029
|
return rs.peaks.map((chPeaks, ch) => {
|
|
5613
6030
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
5614
|
-
return
|
|
6031
|
+
return html10`
|
|
5615
6032
|
<daw-waveform
|
|
5616
6033
|
data-recording-track=${trackId}
|
|
5617
6034
|
data-recording-channel=${ch}
|
|
@@ -5667,6 +6084,14 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5667
6084
|
_getPlayhead() {
|
|
5668
6085
|
return this.shadowRoot?.querySelector("daw-playhead");
|
|
5669
6086
|
}
|
|
6087
|
+
/** True when the controls column should be rendered (and its selector is valid). */
|
|
6088
|
+
get _showControls() {
|
|
6089
|
+
return this._getOrderedTracks().length > 0 || this.indefinitePlayback;
|
|
6090
|
+
}
|
|
6091
|
+
/** True when the ruler header band should be rendered (and its selector is valid). */
|
|
6092
|
+
get _showRuler() {
|
|
6093
|
+
return (this._getOrderedTracks().length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale;
|
|
6094
|
+
}
|
|
5670
6095
|
_getOrderedTracks() {
|
|
5671
6096
|
const domOrder = [...this.querySelectorAll("daw-track")].map(
|
|
5672
6097
|
(el) => el.trackId
|
|
@@ -5708,64 +6133,79 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5708
6133
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
5709
6134
|
};
|
|
5710
6135
|
});
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
style="height: ${t.trackHeight}px;"
|
|
5718
|
-
.trackId=${t.trackId}
|
|
5719
|
-
.trackName=${t.descriptor?.name ?? "Untitled"}
|
|
5720
|
-
.volume=${t.descriptor?.volume ?? 1}
|
|
5721
|
-
.pan=${t.descriptor?.pan ?? 0}
|
|
5722
|
-
.muted=${t.descriptor?.muted ?? false}
|
|
5723
|
-
.soloed=${t.descriptor?.soloed ?? false}
|
|
5724
|
-
></daw-track-controls>
|
|
5725
|
-
`
|
|
5726
|
-
)}
|
|
5727
|
-
</div>` : ""}
|
|
5728
|
-
<div class="scroll-area">
|
|
5729
|
-
<div
|
|
5730
|
-
class="timeline ${this._dragOver ? "drag-over" : ""}"
|
|
5731
|
-
style="width: ${this._totalWidth > 0 ? this._totalWidth + "px" : "100%"};"
|
|
5732
|
-
data-playing=${this._isPlaying}
|
|
5733
|
-
@pointerdown=${this._pointer.onPointerDown}
|
|
5734
|
-
@dragover=${this._onDragOver}
|
|
5735
|
-
@dragleave=${this._onDragLeave}
|
|
5736
|
-
@drop=${this._onDrop}
|
|
5737
|
-
>
|
|
5738
|
-
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ? html9`<daw-ruler
|
|
5739
|
-
.samplesPerPixel=${spp}
|
|
5740
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5741
|
-
.duration=${this._duration}
|
|
5742
|
-
.scaleMode=${this.scaleMode}
|
|
5743
|
-
.ticksPerPixel=${this.ticksPerPixel}
|
|
5744
|
-
.meterEntries=${this._meterEntries}
|
|
5745
|
-
.ppqn=${this.ppqn}
|
|
5746
|
-
.totalWidth=${this._totalWidth}
|
|
5747
|
-
></daw-ruler>` : ""}
|
|
5748
|
-
${this.scaleMode === "beats" ? html9`<daw-grid
|
|
5749
|
-
style="top: ${this.timescale ? 30 : 0}px;"
|
|
5750
|
-
.ticksPerPixel=${this.ticksPerPixel}
|
|
5751
|
-
.meterEntries=${this._meterEntries}
|
|
5752
|
-
.ppqn=${this.ppqn}
|
|
5753
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5754
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5755
|
-
.length=${this._totalWidth}
|
|
5756
|
-
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight + 1, 0) : this._emptyGridHeight}
|
|
5757
|
-
></daw-grid>` : ""}
|
|
5758
|
-
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ? html9`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
5759
|
-
<daw-playhead></daw-playhead>` : ""}
|
|
5760
|
-
${orderedTracks.map((t) => {
|
|
5761
|
-
const channelHeight = this.waveHeight;
|
|
5762
|
-
return html9`
|
|
6136
|
+
const showControls = this._showControls;
|
|
6137
|
+
const showRuler = this._showRuler;
|
|
6138
|
+
return html10`
|
|
6139
|
+
${showRuler ? html10`<div class="header-row" style="height: ${RULER_HEIGHT}px;">
|
|
6140
|
+
${showControls ? html10`<div class="ruler-gap"></div>` : ""}
|
|
6141
|
+
<div class="ruler-viewport" @pointerdown=${this._pointer.onPointerDown}>
|
|
5763
6142
|
<div
|
|
5764
|
-
class="
|
|
5765
|
-
style="
|
|
5766
|
-
data-track-id=${t.trackId}
|
|
6143
|
+
class="ruler-content"
|
|
6144
|
+
style="width: ${this._totalWidth > 0 ? this._totalWidth + "px" : "100%"};"
|
|
5767
6145
|
>
|
|
5768
|
-
|
|
6146
|
+
<daw-ruler
|
|
6147
|
+
.samplesPerPixel=${spp}
|
|
6148
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
6149
|
+
.duration=${this._duration}
|
|
6150
|
+
.scaleMode=${this.scaleMode}
|
|
6151
|
+
.ticksPerPixel=${this.ticksPerPixel}
|
|
6152
|
+
.meterEntries=${this._meterEntries}
|
|
6153
|
+
.ppqn=${this.ppqn}
|
|
6154
|
+
.totalWidth=${this._totalWidth}
|
|
6155
|
+
.rulerHeight=${RULER_HEIGHT}
|
|
6156
|
+
></daw-ruler>
|
|
6157
|
+
</div>
|
|
6158
|
+
</div>
|
|
6159
|
+
</div>` : ""}
|
|
6160
|
+
<div class="body">
|
|
6161
|
+
${showControls ? html10`<div class="controls-viewport">
|
|
6162
|
+
<div class="controls-column">
|
|
6163
|
+
${orderedTracks.map(
|
|
6164
|
+
(t) => html10`
|
|
6165
|
+
<daw-track-controls
|
|
6166
|
+
style="height: ${t.trackHeight}px;"
|
|
6167
|
+
.trackId=${t.trackId}
|
|
6168
|
+
.trackName=${t.descriptor?.name ?? "Untitled"}
|
|
6169
|
+
.volume=${t.descriptor?.volume ?? 1}
|
|
6170
|
+
.pan=${t.descriptor?.pan ?? 0}
|
|
6171
|
+
.muted=${t.descriptor?.muted ?? false}
|
|
6172
|
+
.soloed=${t.descriptor?.soloed ?? false}
|
|
6173
|
+
></daw-track-controls>
|
|
6174
|
+
`
|
|
6175
|
+
)}
|
|
6176
|
+
</div>
|
|
6177
|
+
</div>` : ""}
|
|
6178
|
+
<div class="scroll-area">
|
|
6179
|
+
<div
|
|
6180
|
+
class="timeline ${this._dragOver ? "drag-over" : ""}"
|
|
6181
|
+
style="width: ${this._totalWidth > 0 ? this._totalWidth + "px" : "100%"};"
|
|
6182
|
+
data-playing=${this._isPlaying}
|
|
6183
|
+
@pointerdown=${this._pointer.onPointerDown}
|
|
6184
|
+
@dragover=${this._onDragOver}
|
|
6185
|
+
@dragleave=${this._onDragLeave}
|
|
6186
|
+
@drop=${this._onDrop}
|
|
6187
|
+
>
|
|
6188
|
+
${this.scaleMode === "beats" ? html10`<daw-grid
|
|
6189
|
+
style="top: 0px;"
|
|
6190
|
+
.ticksPerPixel=${this.ticksPerPixel}
|
|
6191
|
+
.meterEntries=${this._meterEntries}
|
|
6192
|
+
.ppqn=${this.ppqn}
|
|
6193
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
6194
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
6195
|
+
.length=${this._totalWidth}
|
|
6196
|
+
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight, 0) : this._emptyGridHeight}
|
|
6197
|
+
></daw-grid>` : ""}
|
|
6198
|
+
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ? html10`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
6199
|
+
<daw-playhead></daw-playhead>` : ""}
|
|
6200
|
+
${orderedTracks.map((t) => {
|
|
6201
|
+
const channelHeight = this.waveHeight;
|
|
6202
|
+
return html10`
|
|
6203
|
+
<div
|
|
6204
|
+
class="track-row ${t.trackId === this._selectedTrackId ? "selected" : ""}"
|
|
6205
|
+
style="height: ${t.trackHeight}px;"
|
|
6206
|
+
data-track-id=${t.trackId}
|
|
6207
|
+
>
|
|
6208
|
+
${t.track.clips.map((clip) => {
|
|
5769
6209
|
const peakData = this._peaksData.get(clip.id);
|
|
5770
6210
|
let clipLeft;
|
|
5771
6211
|
let width;
|
|
@@ -5808,7 +6248,10 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5808
6248
|
const segEndSample = Math.round(segEndAudioSec * sr);
|
|
5809
6249
|
const totalPeaks = clip.durationSamples / baseScale;
|
|
5810
6250
|
clipSegments.push({
|
|
5811
|
-
peakStart: Math.max(
|
|
6251
|
+
peakStart: Math.max(
|
|
6252
|
+
0,
|
|
6253
|
+
(segStartSample - clip.offsetSamples) / baseScale
|
|
6254
|
+
),
|
|
5812
6255
|
peakEnd: Math.min(
|
|
5813
6256
|
totalPeaks,
|
|
5814
6257
|
(segEndSample - clip.offsetSamples) / baseScale
|
|
@@ -5822,78 +6265,79 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5822
6265
|
const channels = segmentChannels ?? peakData?.data ?? [new Int16Array(0)];
|
|
5823
6266
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
5824
6267
|
const chH = this.waveHeight;
|
|
5825
|
-
return
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
data-clip-id=${clip.id}
|
|
5833
|
-
data-track-id=${t.trackId}
|
|
5834
|
-
?data-interactive=${this.interactiveClips}
|
|
5835
|
-
>
|
|
5836
|
-
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
5837
|
-
</div>` : ""}
|
|
5838
|
-
${t.descriptor?.renderMode === "piano-roll" ? html9`<daw-piano-roll
|
|
5839
|
-
style="position:absolute;left:0;top:${hdrH}px;"
|
|
5840
|
-
.midiNotes=${clip.midiNotes ?? []}
|
|
5841
|
-
.length=${peakData?.length ?? width}
|
|
5842
|
-
.waveHeight=${chH * channels.length}
|
|
5843
|
-
.samplesPerPixel=${this._renderSpp}
|
|
5844
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5845
|
-
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
5846
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5847
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5848
|
-
.originX=${clipLeft}
|
|
5849
|
-
?selected=${t.trackId === this._selectedTrackId}
|
|
5850
|
-
></daw-piano-roll>` : t.descriptor?.renderMode === "spectrogram" ? channels.map(
|
|
5851
|
-
(_chPeaks, chIdx) => html9`<daw-spectrogram
|
|
5852
|
-
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;height:${chH}px;width:${peakData?.length ?? width}px;"
|
|
5853
|
-
.clipId=${clip.id}
|
|
5854
|
-
.trackId=${t.trackId}
|
|
5855
|
-
.channelIndex=${chIdx}
|
|
5856
|
-
.length=${peakData?.length ?? width}
|
|
5857
|
-
.waveHeight=${chH}
|
|
5858
|
-
.samplesPerPixel=${this._renderSpp}
|
|
5859
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5860
|
-
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
5861
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5862
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5863
|
-
.originX=${clipLeft}
|
|
5864
|
-
></daw-spectrogram>`
|
|
5865
|
-
) : channels.map(
|
|
5866
|
-
(chPeaks, chIdx) => html9` <daw-waveform
|
|
5867
|
-
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
5868
|
-
.peaks=${chPeaks}
|
|
5869
|
-
.length=${peakData?.length ?? width}
|
|
5870
|
-
.waveHeight=${chH}
|
|
5871
|
-
.barWidth=${this.barWidth}
|
|
5872
|
-
.barGap=${this.barGap}
|
|
5873
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5874
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5875
|
-
.originX=${clipLeft}
|
|
5876
|
-
.segments=${clipSegments}
|
|
5877
|
-
></daw-waveform>`
|
|
5878
|
-
)}
|
|
5879
|
-
${this.interactiveClips ? html9` <div
|
|
5880
|
-
class="clip-boundary"
|
|
5881
|
-
data-boundary-edge="left"
|
|
5882
|
-
data-clip-id=${clip.id}
|
|
5883
|
-
data-track-id=${t.trackId}
|
|
5884
|
-
></div>
|
|
5885
|
-
<div
|
|
5886
|
-
class="clip-boundary"
|
|
5887
|
-
data-boundary-edge="right"
|
|
6268
|
+
return html10` <div
|
|
6269
|
+
class="clip-container"
|
|
6270
|
+
style="left:${clipLeft}px;top:0;width:${width}px;height:${t.trackHeight}px;"
|
|
6271
|
+
data-clip-id=${clip.id}
|
|
6272
|
+
>
|
|
6273
|
+
${hdrH > 0 ? html10`<div
|
|
6274
|
+
class="clip-header"
|
|
5888
6275
|
data-clip-id=${clip.id}
|
|
5889
6276
|
data-track-id=${t.trackId}
|
|
5890
|
-
|
|
5891
|
-
|
|
6277
|
+
?data-interactive=${this.interactiveClips}
|
|
6278
|
+
>
|
|
6279
|
+
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
6280
|
+
</div>` : ""}
|
|
6281
|
+
${t.descriptor?.renderMode === "piano-roll" ? html10`<daw-piano-roll
|
|
6282
|
+
style="position:absolute;left:0;top:${hdrH}px;"
|
|
6283
|
+
.midiNotes=${clip.midiNotes ?? []}
|
|
6284
|
+
.length=${peakData?.length ?? width}
|
|
6285
|
+
.waveHeight=${chH * channels.length}
|
|
6286
|
+
.samplesPerPixel=${this._renderSpp}
|
|
6287
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
6288
|
+
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
6289
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
6290
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
6291
|
+
.originX=${clipLeft}
|
|
6292
|
+
?selected=${t.trackId === this._selectedTrackId}
|
|
6293
|
+
></daw-piano-roll>` : t.descriptor?.renderMode === "spectrogram" ? channels.map(
|
|
6294
|
+
(_chPeaks, chIdx) => html10`<daw-spectrogram
|
|
6295
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;height:${chH}px;width:${peakData?.length ?? width}px;"
|
|
6296
|
+
.clipId=${clip.id}
|
|
6297
|
+
.trackId=${t.trackId}
|
|
6298
|
+
.channelIndex=${chIdx}
|
|
6299
|
+
.length=${peakData?.length ?? width}
|
|
6300
|
+
.waveHeight=${chH}
|
|
6301
|
+
.samplesPerPixel=${this._renderSpp}
|
|
6302
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
6303
|
+
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
6304
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
6305
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
6306
|
+
.originX=${clipLeft}
|
|
6307
|
+
></daw-spectrogram>`
|
|
6308
|
+
) : channels.map(
|
|
6309
|
+
(chPeaks, chIdx) => html10` <daw-waveform
|
|
6310
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
6311
|
+
.peaks=${chPeaks}
|
|
6312
|
+
.length=${peakData?.length ?? width}
|
|
6313
|
+
.waveHeight=${chH}
|
|
6314
|
+
.barWidth=${this.barWidth}
|
|
6315
|
+
.barGap=${this.barGap}
|
|
6316
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
6317
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
6318
|
+
.originX=${clipLeft}
|
|
6319
|
+
.segments=${clipSegments}
|
|
6320
|
+
></daw-waveform>`
|
|
6321
|
+
)}
|
|
6322
|
+
${this.interactiveClips ? html10` <div
|
|
6323
|
+
class="clip-boundary"
|
|
6324
|
+
data-boundary-edge="left"
|
|
6325
|
+
data-clip-id=${clip.id}
|
|
6326
|
+
data-track-id=${t.trackId}
|
|
6327
|
+
></div>
|
|
6328
|
+
<div
|
|
6329
|
+
class="clip-boundary"
|
|
6330
|
+
data-boundary-edge="right"
|
|
6331
|
+
data-clip-id=${clip.id}
|
|
6332
|
+
data-track-id=${t.trackId}
|
|
6333
|
+
></div>` : ""}
|
|
6334
|
+
</div>`;
|
|
5892
6335
|
})}
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
6336
|
+
${this._renderRecordingPreview(t.trackId, channelHeight)}
|
|
6337
|
+
</div>
|
|
6338
|
+
`;
|
|
5896
6339
|
})}
|
|
6340
|
+
</div>
|
|
5897
6341
|
</div>
|
|
5898
6342
|
</div>
|
|
5899
6343
|
<slot></slot>
|
|
@@ -5902,21 +6346,48 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5902
6346
|
};
|
|
5903
6347
|
DawEditorElement.styles = [
|
|
5904
6348
|
hostStyles,
|
|
5905
|
-
|
|
6349
|
+
css10`
|
|
5906
6350
|
:host {
|
|
5907
6351
|
display: flex;
|
|
6352
|
+
flex-direction: column;
|
|
5908
6353
|
position: relative;
|
|
5909
6354
|
background: var(--daw-background, #1a1a2e);
|
|
5910
6355
|
overflow: hidden;
|
|
5911
6356
|
}
|
|
5912
|
-
.
|
|
6357
|
+
.header-row {
|
|
6358
|
+
display: flex;
|
|
6359
|
+
flex-shrink: 0;
|
|
6360
|
+
}
|
|
6361
|
+
.ruler-gap {
|
|
6362
|
+
flex-shrink: 0;
|
|
6363
|
+
width: var(--daw-controls-width, 180px);
|
|
6364
|
+
}
|
|
6365
|
+
.ruler-viewport {
|
|
6366
|
+
flex: 1;
|
|
6367
|
+
position: relative;
|
|
6368
|
+
overflow: hidden;
|
|
6369
|
+
cursor: text;
|
|
6370
|
+
}
|
|
6371
|
+
.ruler-content {
|
|
6372
|
+
will-change: transform;
|
|
6373
|
+
}
|
|
6374
|
+
.body {
|
|
6375
|
+
flex: 1;
|
|
6376
|
+
min-height: 0;
|
|
6377
|
+
display: flex;
|
|
6378
|
+
}
|
|
6379
|
+
.controls-viewport {
|
|
5913
6380
|
flex-shrink: 0;
|
|
5914
6381
|
width: var(--daw-controls-width, 180px);
|
|
6382
|
+
overflow: hidden;
|
|
6383
|
+
}
|
|
6384
|
+
.controls-column {
|
|
6385
|
+
will-change: transform;
|
|
5915
6386
|
}
|
|
5916
6387
|
.scroll-area {
|
|
5917
6388
|
flex: 1;
|
|
5918
|
-
overflow
|
|
5919
|
-
overflow-
|
|
6389
|
+
overflow: auto;
|
|
6390
|
+
overflow-anchor: none;
|
|
5920
6391
|
min-height: var(--daw-min-height, 200px);
|
|
5921
6392
|
}
|
|
5922
6393
|
.timeline {
|
|
@@ -5926,6 +6397,7 @@ DawEditorElement.styles = [
|
|
|
5926
6397
|
}
|
|
5927
6398
|
.track-row {
|
|
5928
6399
|
position: relative;
|
|
6400
|
+
box-sizing: border-box;
|
|
5929
6401
|
background: var(--daw-track-background, #16213e);
|
|
5930
6402
|
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
5931
6403
|
}
|
|
@@ -5950,70 +6422,70 @@ DawEditorElement.styles = [
|
|
|
5950
6422
|
];
|
|
5951
6423
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
5952
6424
|
__decorateClass([
|
|
5953
|
-
|
|
6425
|
+
property9({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
5954
6426
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
5955
6427
|
__decorateClass([
|
|
5956
|
-
|
|
6428
|
+
property9({ type: Number, attribute: "wave-height" })
|
|
5957
6429
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
5958
6430
|
__decorateClass([
|
|
5959
|
-
|
|
6431
|
+
property9({ type: Boolean })
|
|
5960
6432
|
], DawEditorElement.prototype, "timescale", 2);
|
|
5961
6433
|
__decorateClass([
|
|
5962
|
-
|
|
6434
|
+
property9({ type: Boolean })
|
|
5963
6435
|
], DawEditorElement.prototype, "mono", 2);
|
|
5964
6436
|
__decorateClass([
|
|
5965
|
-
|
|
6437
|
+
property9({ type: Number, attribute: "bar-width" })
|
|
5966
6438
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
5967
6439
|
__decorateClass([
|
|
5968
|
-
|
|
6440
|
+
property9({ type: Number, attribute: "bar-gap" })
|
|
5969
6441
|
], DawEditorElement.prototype, "barGap", 2);
|
|
5970
6442
|
__decorateClass([
|
|
5971
|
-
|
|
6443
|
+
property9({ type: Boolean, attribute: "file-drop" })
|
|
5972
6444
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
5973
6445
|
__decorateClass([
|
|
5974
|
-
|
|
6446
|
+
property9({ type: Boolean, attribute: "clip-headers" })
|
|
5975
6447
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
5976
6448
|
__decorateClass([
|
|
5977
|
-
|
|
6449
|
+
property9({ type: Number, attribute: "clip-header-height" })
|
|
5978
6450
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
5979
6451
|
__decorateClass([
|
|
5980
|
-
|
|
6452
|
+
property9({ type: Boolean, attribute: "interactive-clips" })
|
|
5981
6453
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
5982
6454
|
__decorateClass([
|
|
5983
|
-
|
|
6455
|
+
property9({ type: Boolean, attribute: "indefinite-playback" })
|
|
5984
6456
|
], DawEditorElement.prototype, "indefinitePlayback", 2);
|
|
5985
6457
|
__decorateClass([
|
|
5986
|
-
|
|
6458
|
+
property9({ attribute: false, noAccessor: true })
|
|
5987
6459
|
], DawEditorElement.prototype, "spectrogramConfig", 1);
|
|
5988
6460
|
__decorateClass([
|
|
5989
|
-
|
|
6461
|
+
property9({ attribute: false, noAccessor: true })
|
|
5990
6462
|
], DawEditorElement.prototype, "spectrogramColorMap", 1);
|
|
5991
6463
|
__decorateClass([
|
|
5992
|
-
|
|
6464
|
+
property9({ type: String, attribute: "scale-mode" })
|
|
5993
6465
|
], DawEditorElement.prototype, "scaleMode", 2);
|
|
5994
6466
|
__decorateClass([
|
|
5995
|
-
|
|
6467
|
+
property9({ type: Number, attribute: "ticks-per-pixel", noAccessor: true })
|
|
5996
6468
|
], DawEditorElement.prototype, "ticksPerPixel", 1);
|
|
5997
6469
|
__decorateClass([
|
|
5998
|
-
|
|
6470
|
+
property9({ type: Number, noAccessor: true })
|
|
5999
6471
|
], DawEditorElement.prototype, "bpm", 1);
|
|
6000
6472
|
__decorateClass([
|
|
6001
|
-
|
|
6473
|
+
property9({ attribute: false })
|
|
6002
6474
|
], DawEditorElement.prototype, "timeSignature", 2);
|
|
6003
6475
|
__decorateClass([
|
|
6004
|
-
|
|
6476
|
+
property9({ attribute: false })
|
|
6005
6477
|
], DawEditorElement.prototype, "meterEntries", 2);
|
|
6006
6478
|
__decorateClass([
|
|
6007
|
-
|
|
6479
|
+
property9({ type: Number, noAccessor: true })
|
|
6008
6480
|
], DawEditorElement.prototype, "ppqn", 1);
|
|
6009
6481
|
__decorateClass([
|
|
6010
|
-
|
|
6482
|
+
property9({ type: String, attribute: "snap-to" })
|
|
6011
6483
|
], DawEditorElement.prototype, "snapTo", 2);
|
|
6012
6484
|
__decorateClass([
|
|
6013
|
-
|
|
6485
|
+
property9({ attribute: false })
|
|
6014
6486
|
], DawEditorElement.prototype, "secondsToTicks", 2);
|
|
6015
6487
|
__decorateClass([
|
|
6016
|
-
|
|
6488
|
+
property9({ attribute: false })
|
|
6017
6489
|
], DawEditorElement.prototype, "ticksToSeconds", 2);
|
|
6018
6490
|
__decorateClass([
|
|
6019
6491
|
state3()
|
|
@@ -6037,246 +6509,15 @@ __decorateClass([
|
|
|
6037
6509
|
state3()
|
|
6038
6510
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
6039
6511
|
__decorateClass([
|
|
6040
|
-
|
|
6512
|
+
property9({ attribute: false })
|
|
6041
6513
|
], DawEditorElement.prototype, "adapter", 1);
|
|
6042
6514
|
__decorateClass([
|
|
6043
|
-
|
|
6515
|
+
property9({ attribute: "eager-resume" })
|
|
6044
6516
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
6045
6517
|
DawEditorElement = __decorateClass([
|
|
6046
|
-
|
|
6518
|
+
customElement13("daw-editor")
|
|
6047
6519
|
], DawEditorElement);
|
|
6048
6520
|
|
|
6049
|
-
// src/elements/daw-ruler.ts
|
|
6050
|
-
import { LitElement as LitElement11, html as html10, css as css10 } from "lit";
|
|
6051
|
-
import { customElement as customElement13, property as property9 } from "lit/decorators.js";
|
|
6052
|
-
|
|
6053
|
-
// src/utils/time-format.ts
|
|
6054
|
-
function formatTime(milliseconds) {
|
|
6055
|
-
const seconds = Math.floor(milliseconds / 1e3);
|
|
6056
|
-
const s = seconds % 60;
|
|
6057
|
-
const m = (seconds - s) / 60;
|
|
6058
|
-
return `${m}:${String(s).padStart(2, "0")}`;
|
|
6059
|
-
}
|
|
6060
|
-
|
|
6061
|
-
// src/utils/smart-scale.ts
|
|
6062
|
-
var timeinfo = /* @__PURE__ */ new Map([
|
|
6063
|
-
[700, { marker: 1e3, bigStep: 500, smallStep: 100 }],
|
|
6064
|
-
[1500, { marker: 2e3, bigStep: 1e3, smallStep: 200 }],
|
|
6065
|
-
[2500, { marker: 2e3, bigStep: 1e3, smallStep: 500 }],
|
|
6066
|
-
[5e3, { marker: 5e3, bigStep: 1e3, smallStep: 500 }],
|
|
6067
|
-
[1e4, { marker: 1e4, bigStep: 5e3, smallStep: 1e3 }],
|
|
6068
|
-
[12e3, { marker: 15e3, bigStep: 5e3, smallStep: 1e3 }],
|
|
6069
|
-
[Infinity, { marker: 3e4, bigStep: 1e4, smallStep: 5e3 }]
|
|
6070
|
-
]);
|
|
6071
|
-
function getScaleInfo(samplesPerPixel) {
|
|
6072
|
-
for (const [resolution, config] of timeinfo) {
|
|
6073
|
-
if (samplesPerPixel < resolution) {
|
|
6074
|
-
return config;
|
|
6075
|
-
}
|
|
6076
|
-
}
|
|
6077
|
-
return { marker: 3e4, bigStep: 1e4, smallStep: 5e3 };
|
|
6078
|
-
}
|
|
6079
|
-
function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight) {
|
|
6080
|
-
const widthX = Math.ceil(duration * sampleRate / samplesPerPixel);
|
|
6081
|
-
const config = getScaleInfo(samplesPerPixel);
|
|
6082
|
-
const { marker, bigStep, smallStep } = config;
|
|
6083
|
-
const canvasInfo = /* @__PURE__ */ new Map();
|
|
6084
|
-
const labels = [];
|
|
6085
|
-
const pixPerSec = sampleRate / samplesPerPixel;
|
|
6086
|
-
for (let counter = 0; ; counter += smallStep) {
|
|
6087
|
-
const pix = Math.floor(counter / 1e3 * pixPerSec);
|
|
6088
|
-
if (pix >= widthX) break;
|
|
6089
|
-
if (counter % marker === 0) {
|
|
6090
|
-
canvasInfo.set(pix, rulerHeight);
|
|
6091
|
-
labels.push({ pix, text: formatTime(counter) });
|
|
6092
|
-
} else if (counter % bigStep === 0) {
|
|
6093
|
-
canvasInfo.set(pix, Math.floor(rulerHeight / 2));
|
|
6094
|
-
} else if (counter % smallStep === 0) {
|
|
6095
|
-
canvasInfo.set(pix, Math.floor(rulerHeight / 5));
|
|
6096
|
-
}
|
|
6097
|
-
}
|
|
6098
|
-
return { widthX, canvasInfo, labels };
|
|
6099
|
-
}
|
|
6100
|
-
|
|
6101
|
-
// src/elements/daw-ruler.ts
|
|
6102
|
-
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
6103
|
-
var DawRulerElement = class extends LitElement11 {
|
|
6104
|
-
constructor() {
|
|
6105
|
-
super(...arguments);
|
|
6106
|
-
this.samplesPerPixel = 1024;
|
|
6107
|
-
this.sampleRate = 48e3;
|
|
6108
|
-
this.duration = 0;
|
|
6109
|
-
this.rulerHeight = 30;
|
|
6110
|
-
this.scaleMode = "temporal";
|
|
6111
|
-
this.ticksPerPixel = 4;
|
|
6112
|
-
this.meterEntries = [
|
|
6113
|
-
{ tick: 0, numerator: 4, denominator: 4 }
|
|
6114
|
-
];
|
|
6115
|
-
this.ppqn = 960;
|
|
6116
|
-
this.totalWidth = 0;
|
|
6117
|
-
this._tickData = null;
|
|
6118
|
-
this._musicalTickData = null;
|
|
6119
|
-
}
|
|
6120
|
-
willUpdate() {
|
|
6121
|
-
if (this.scaleMode === "beats" && this.totalWidth > 0) {
|
|
6122
|
-
this._musicalTickData = getCachedMusicalTicks({
|
|
6123
|
-
meterEntries: this.meterEntries,
|
|
6124
|
-
ticksPerPixel: this.ticksPerPixel,
|
|
6125
|
-
startPixel: 0,
|
|
6126
|
-
endPixel: this.totalWidth,
|
|
6127
|
-
ppqn: this.ppqn
|
|
6128
|
-
});
|
|
6129
|
-
this._tickData = null;
|
|
6130
|
-
} else if (this.duration > 0 || this.totalWidth > 0) {
|
|
6131
|
-
const widthDerivedDuration = this.totalWidth * this.samplesPerPixel / this.sampleRate;
|
|
6132
|
-
const effectiveDuration = Math.max(this.duration, widthDerivedDuration);
|
|
6133
|
-
this._musicalTickData = null;
|
|
6134
|
-
this._tickData = computeTemporalTicks(
|
|
6135
|
-
this.samplesPerPixel,
|
|
6136
|
-
this.sampleRate,
|
|
6137
|
-
effectiveDuration,
|
|
6138
|
-
this.rulerHeight
|
|
6139
|
-
);
|
|
6140
|
-
} else {
|
|
6141
|
-
this._musicalTickData = null;
|
|
6142
|
-
this._tickData = null;
|
|
6143
|
-
}
|
|
6144
|
-
}
|
|
6145
|
-
render() {
|
|
6146
|
-
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
6147
|
-
if (widthX <= 0) return html10``;
|
|
6148
|
-
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH4);
|
|
6149
|
-
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
6150
|
-
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
6151
|
-
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
6152
|
-
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
6153
|
-
return html10`
|
|
6154
|
-
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
6155
|
-
${indices.map((i) => {
|
|
6156
|
-
const width = Math.min(MAX_CANVAS_WIDTH4, widthX - i * MAX_CANVAS_WIDTH4);
|
|
6157
|
-
return html10`
|
|
6158
|
-
<canvas
|
|
6159
|
-
data-index=${i}
|
|
6160
|
-
width=${width * dpr}
|
|
6161
|
-
height=${this.rulerHeight * dpr}
|
|
6162
|
-
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
6163
|
-
></canvas>
|
|
6164
|
-
`;
|
|
6165
|
-
})}
|
|
6166
|
-
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
6167
|
-
(t) => html10`<span
|
|
6168
|
-
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
6169
|
-
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
6170
|
-
>${t.label}</span
|
|
6171
|
-
>`
|
|
6172
|
-
) : temporalLabels.map(
|
|
6173
|
-
({ pix, text }) => html10`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
6174
|
-
)}
|
|
6175
|
-
</div>
|
|
6176
|
-
`;
|
|
6177
|
-
}
|
|
6178
|
-
updated() {
|
|
6179
|
-
this._drawTicks();
|
|
6180
|
-
}
|
|
6181
|
-
_drawTicks() {
|
|
6182
|
-
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
6183
|
-
if (!canvases) return;
|
|
6184
|
-
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
6185
|
-
const rulerColor = getComputedStyle(this).getPropertyValue("--daw-ruler-color").trim() || "#c49a6c";
|
|
6186
|
-
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
6187
|
-
for (const canvas of canvases) {
|
|
6188
|
-
const idx = Number(canvas.dataset.index);
|
|
6189
|
-
const ctx = canvas.getContext("2d");
|
|
6190
|
-
if (!ctx) continue;
|
|
6191
|
-
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, widthX - idx * MAX_CANVAS_WIDTH4);
|
|
6192
|
-
const globalOffset = idx * MAX_CANVAS_WIDTH4;
|
|
6193
|
-
ctx.resetTransform();
|
|
6194
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6195
|
-
ctx.scale(dpr, dpr);
|
|
6196
|
-
ctx.strokeStyle = rulerColor;
|
|
6197
|
-
ctx.lineWidth = 1;
|
|
6198
|
-
if (this.scaleMode === "beats" && this._musicalTickData) {
|
|
6199
|
-
const h = this.rulerHeight;
|
|
6200
|
-
for (const tick of this._musicalTickData.ticks) {
|
|
6201
|
-
const localX = tick.pixel - globalOffset;
|
|
6202
|
-
if (localX < 0 || localX >= canvasWidth) continue;
|
|
6203
|
-
const tickH = tick.type === "major" ? h * 0.6 : tick.type === "minor" ? h * 0.35 : h * 0.15;
|
|
6204
|
-
ctx.globalAlpha = tick.type === "major" ? 1 : 0.5;
|
|
6205
|
-
ctx.beginPath();
|
|
6206
|
-
ctx.moveTo(localX + 0.5, h);
|
|
6207
|
-
ctx.lineTo(localX + 0.5, h - tickH);
|
|
6208
|
-
ctx.stroke();
|
|
6209
|
-
}
|
|
6210
|
-
ctx.globalAlpha = 1;
|
|
6211
|
-
} else if (this._tickData) {
|
|
6212
|
-
for (const [pix, height] of this._tickData.canvasInfo) {
|
|
6213
|
-
const localX = pix - globalOffset;
|
|
6214
|
-
if (localX < 0 || localX >= canvasWidth) continue;
|
|
6215
|
-
ctx.beginPath();
|
|
6216
|
-
ctx.moveTo(localX + 0.5, this.rulerHeight);
|
|
6217
|
-
ctx.lineTo(localX + 0.5, this.rulerHeight - height);
|
|
6218
|
-
ctx.stroke();
|
|
6219
|
-
}
|
|
6220
|
-
}
|
|
6221
|
-
}
|
|
6222
|
-
}
|
|
6223
|
-
};
|
|
6224
|
-
DawRulerElement.styles = css10`
|
|
6225
|
-
:host {
|
|
6226
|
-
display: block;
|
|
6227
|
-
position: relative;
|
|
6228
|
-
background: var(--daw-ruler-background, #0f0f1a);
|
|
6229
|
-
}
|
|
6230
|
-
.container {
|
|
6231
|
-
position: relative;
|
|
6232
|
-
}
|
|
6233
|
-
canvas {
|
|
6234
|
-
position: absolute;
|
|
6235
|
-
top: 0;
|
|
6236
|
-
}
|
|
6237
|
-
.label {
|
|
6238
|
-
position: absolute;
|
|
6239
|
-
font-size: 0.7rem;
|
|
6240
|
-
line-height: 1;
|
|
6241
|
-
white-space: nowrap;
|
|
6242
|
-
color: var(--daw-ruler-color, #c49a6c);
|
|
6243
|
-
top: 1px;
|
|
6244
|
-
}
|
|
6245
|
-
.label.centered {
|
|
6246
|
-
transform: translateX(-50%);
|
|
6247
|
-
}
|
|
6248
|
-
`;
|
|
6249
|
-
__decorateClass([
|
|
6250
|
-
property9({ type: Number, attribute: false })
|
|
6251
|
-
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
6252
|
-
__decorateClass([
|
|
6253
|
-
property9({ type: Number, attribute: false })
|
|
6254
|
-
], DawRulerElement.prototype, "sampleRate", 2);
|
|
6255
|
-
__decorateClass([
|
|
6256
|
-
property9({ type: Number, attribute: false })
|
|
6257
|
-
], DawRulerElement.prototype, "duration", 2);
|
|
6258
|
-
__decorateClass([
|
|
6259
|
-
property9({ type: Number, attribute: false })
|
|
6260
|
-
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
6261
|
-
__decorateClass([
|
|
6262
|
-
property9({ type: String, attribute: false })
|
|
6263
|
-
], DawRulerElement.prototype, "scaleMode", 2);
|
|
6264
|
-
__decorateClass([
|
|
6265
|
-
property9({ type: Number, attribute: false })
|
|
6266
|
-
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
6267
|
-
__decorateClass([
|
|
6268
|
-
property9({ attribute: false })
|
|
6269
|
-
], DawRulerElement.prototype, "meterEntries", 2);
|
|
6270
|
-
__decorateClass([
|
|
6271
|
-
property9({ type: Number, attribute: false })
|
|
6272
|
-
], DawRulerElement.prototype, "ppqn", 2);
|
|
6273
|
-
__decorateClass([
|
|
6274
|
-
property9({ type: Number, attribute: false })
|
|
6275
|
-
], DawRulerElement.prototype, "totalWidth", 2);
|
|
6276
|
-
DawRulerElement = __decorateClass([
|
|
6277
|
-
customElement13("daw-ruler")
|
|
6278
|
-
], DawRulerElement);
|
|
6279
|
-
|
|
6280
6521
|
// src/elements/daw-selection.ts
|
|
6281
6522
|
import { LitElement as LitElement12, html as html11, css as css11 } from "lit";
|
|
6282
6523
|
import { customElement as customElement14, property as property10 } from "lit/decorators.js";
|