@dawcore/components 0.0.19 → 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 +157 -137
- package/dist/index.d.ts +157 -137
- package/dist/index.js +895 -613
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +765 -480
- package/dist/index.mjs.map +1 -1
- package/package.json +25 -16
package/dist/index.mjs
CHANGED
|
@@ -174,7 +174,7 @@ var DawTrackElement = class extends LitElement2 {
|
|
|
174
174
|
this.pan = 0;
|
|
175
175
|
this.muted = false;
|
|
176
176
|
this.soloed = false;
|
|
177
|
-
this.
|
|
177
|
+
this._renderMode = "waveform";
|
|
178
178
|
this.spectrogramConfig = null;
|
|
179
179
|
this.trackId = crypto.randomUUID();
|
|
180
180
|
// Track removal is detected by the editor's MutationObserver,
|
|
@@ -182,6 +182,21 @@ var DawTrackElement = class extends LitElement2 {
|
|
|
182
182
|
// cannot bubble events to ancestors).
|
|
183
183
|
this._hasRendered = false;
|
|
184
184
|
}
|
|
185
|
+
get renderMode() {
|
|
186
|
+
return this._renderMode;
|
|
187
|
+
}
|
|
188
|
+
set renderMode(value) {
|
|
189
|
+
const old = this._renderMode;
|
|
190
|
+
let next = value;
|
|
191
|
+
if (next === "both") {
|
|
192
|
+
console.warn(
|
|
193
|
+
`[dawcore] <daw-track render-mode="both"> is not yet supported; falling back to 'spectrogram'`
|
|
194
|
+
);
|
|
195
|
+
next = "spectrogram";
|
|
196
|
+
}
|
|
197
|
+
this._renderMode = next;
|
|
198
|
+
this.requestUpdate("renderMode", old);
|
|
199
|
+
}
|
|
185
200
|
// Light DOM so <daw-clip> children are queryable.
|
|
186
201
|
createRenderRoot() {
|
|
187
202
|
return this;
|
|
@@ -244,8 +259,8 @@ __decorateClass([
|
|
|
244
259
|
property2({ type: Boolean })
|
|
245
260
|
], DawTrackElement.prototype, "soloed", 2);
|
|
246
261
|
__decorateClass([
|
|
247
|
-
property2({ attribute: "render-mode" })
|
|
248
|
-
], DawTrackElement.prototype, "renderMode",
|
|
262
|
+
property2({ attribute: "render-mode", noAccessor: true })
|
|
263
|
+
], DawTrackElement.prototype, "renderMode", 1);
|
|
249
264
|
__decorateClass([
|
|
250
265
|
property2({ attribute: false })
|
|
251
266
|
], DawTrackElement.prototype, "spectrogramConfig", 2);
|
|
@@ -1181,8 +1196,8 @@ DawStopButtonElement = __decorateClass([
|
|
|
1181
1196
|
], DawStopButtonElement);
|
|
1182
1197
|
|
|
1183
1198
|
// src/elements/daw-editor.ts
|
|
1184
|
-
import { LitElement as
|
|
1185
|
-
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";
|
|
1186
1201
|
|
|
1187
1202
|
// src/types.ts
|
|
1188
1203
|
function isDomClip(desc) {
|
|
@@ -1666,10 +1681,268 @@ var PeakPipeline = class {
|
|
|
1666
1681
|
}
|
|
1667
1682
|
};
|
|
1668
1683
|
|
|
1669
|
-
// src/elements/daw-
|
|
1684
|
+
// src/elements/daw-ruler.ts
|
|
1670
1685
|
import { LitElement as LitElement8, html as html7, css as css6 } from "lit";
|
|
1671
1686
|
import { customElement as customElement10, property as property6 } from "lit/decorators.js";
|
|
1672
|
-
|
|
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 {
|
|
1673
1946
|
constructor() {
|
|
1674
1947
|
super(...arguments);
|
|
1675
1948
|
this.trackId = null;
|
|
@@ -1703,9 +1976,20 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1703
1976
|
);
|
|
1704
1977
|
};
|
|
1705
1978
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
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
|
+
}
|
|
1990
|
+
_dispatchControl(prop, value) {
|
|
1991
|
+
if (!this.trackId) return;
|
|
1992
|
+
this.dispatchEvent(
|
|
1709
1993
|
new CustomEvent("daw-track-control", {
|
|
1710
1994
|
bubbles: true,
|
|
1711
1995
|
composed: true,
|
|
@@ -1717,7 +2001,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1717
2001
|
const volPercent = Math.round(this.volume * 100);
|
|
1718
2002
|
const panPercent = Math.round(Math.abs(this.pan) * 100);
|
|
1719
2003
|
const panDisplay = this.pan === 0 ? "C" : (this.pan > 0 ? "R" : "L") + panPercent;
|
|
1720
|
-
return
|
|
2004
|
+
return html8`
|
|
1721
2005
|
<div class="header">
|
|
1722
2006
|
<span class="name" title=${this.trackName}>${this.trackName || "Untitled"}</span>
|
|
1723
2007
|
<button class="remove-btn" @click=${this._onRemoveClick} title="Remove track">
|
|
@@ -1736,7 +2020,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1736
2020
|
S
|
|
1737
2021
|
</button>
|
|
1738
2022
|
</div>
|
|
1739
|
-
<div class="slider-row">
|
|
2023
|
+
<div class="slider-row vol-row">
|
|
1740
2024
|
<span class="slider-label">
|
|
1741
2025
|
<span class="slider-label-name">Vol</span>
|
|
1742
2026
|
<span class="slider-label-value">${volPercent}%</span>
|
|
@@ -1750,7 +2034,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1750
2034
|
@input=${this._onVolumeInput}
|
|
1751
2035
|
/>
|
|
1752
2036
|
</div>
|
|
1753
|
-
<div class="slider-row">
|
|
2037
|
+
<div class="slider-row pan-row">
|
|
1754
2038
|
<span class="slider-label">
|
|
1755
2039
|
<span class="slider-label-name">Pan</span>
|
|
1756
2040
|
<span class="slider-label-value">${panDisplay}</span>
|
|
@@ -1767,7 +2051,7 @@ var DawTrackControlsElement = class extends LitElement8 {
|
|
|
1767
2051
|
`;
|
|
1768
2052
|
}
|
|
1769
2053
|
};
|
|
1770
|
-
DawTrackControlsElement.styles =
|
|
2054
|
+
DawTrackControlsElement.styles = css7`
|
|
1771
2055
|
:host {
|
|
1772
2056
|
display: flex;
|
|
1773
2057
|
flex-direction: column;
|
|
@@ -1780,6 +2064,7 @@ DawTrackControlsElement.styles = css6`
|
|
|
1780
2064
|
font-family: system-ui, sans-serif;
|
|
1781
2065
|
font-size: 11px;
|
|
1782
2066
|
overflow: hidden;
|
|
2067
|
+
container-type: size;
|
|
1783
2068
|
}
|
|
1784
2069
|
.header {
|
|
1785
2070
|
display: flex;
|
|
@@ -1899,64 +2184,52 @@ DawTrackControlsElement.styles = css6`
|
|
|
1899
2184
|
border: none;
|
|
1900
2185
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
|
1901
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
|
+
}
|
|
1902
2204
|
`;
|
|
1903
2205
|
__decorateClass([
|
|
1904
|
-
|
|
2206
|
+
property7({ attribute: false })
|
|
1905
2207
|
], DawTrackControlsElement.prototype, "trackId", 2);
|
|
1906
2208
|
__decorateClass([
|
|
1907
|
-
|
|
2209
|
+
property7({ attribute: false })
|
|
1908
2210
|
], DawTrackControlsElement.prototype, "trackName", 2);
|
|
1909
2211
|
__decorateClass([
|
|
1910
|
-
|
|
2212
|
+
property7({ type: Number, attribute: false })
|
|
1911
2213
|
], DawTrackControlsElement.prototype, "volume", 2);
|
|
1912
2214
|
__decorateClass([
|
|
1913
|
-
|
|
2215
|
+
property7({ type: Number, attribute: false })
|
|
1914
2216
|
], DawTrackControlsElement.prototype, "pan", 2);
|
|
1915
2217
|
__decorateClass([
|
|
1916
|
-
|
|
2218
|
+
property7({ type: Boolean, attribute: false })
|
|
1917
2219
|
], DawTrackControlsElement.prototype, "muted", 2);
|
|
1918
2220
|
__decorateClass([
|
|
1919
|
-
|
|
2221
|
+
property7({ type: Boolean, attribute: false })
|
|
1920
2222
|
], DawTrackControlsElement.prototype, "soloed", 2);
|
|
1921
2223
|
DawTrackControlsElement = __decorateClass([
|
|
1922
|
-
|
|
2224
|
+
customElement11("daw-track-controls")
|
|
1923
2225
|
], DawTrackControlsElement);
|
|
1924
2226
|
|
|
1925
2227
|
// src/elements/daw-grid.ts
|
|
1926
|
-
import { LitElement as
|
|
1927
|
-
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";
|
|
1928
2230
|
import { MIN_PIXELS_PER_UNIT } from "@waveform-playlist/core";
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
import { computeMusicalTicks } from "@waveform-playlist/core";
|
|
1932
|
-
var cachedParams = null;
|
|
1933
|
-
var cachedResult = null;
|
|
1934
|
-
function meterEntriesMatch(a, b) {
|
|
1935
|
-
if (a.length !== b.length) return false;
|
|
1936
|
-
for (let i = 0; i < a.length; i++) {
|
|
1937
|
-
if (a[i].tick !== b[i].tick || a[i].numerator !== b[i].numerator || a[i].denominator !== b[i].denominator)
|
|
1938
|
-
return false;
|
|
1939
|
-
}
|
|
1940
|
-
return true;
|
|
1941
|
-
}
|
|
1942
|
-
function paramsMatch(a, b) {
|
|
1943
|
-
return a.ticksPerPixel === b.ticksPerPixel && a.startPixel === b.startPixel && a.endPixel === b.endPixel && meterEntriesMatch(a.meterEntries, b.meterEntries) && (a.ppqn ?? 960) === (b.ppqn ?? 960);
|
|
1944
|
-
}
|
|
1945
|
-
function getCachedMusicalTicks(params) {
|
|
1946
|
-
if (cachedParams && cachedResult && paramsMatch(cachedParams, params)) {
|
|
1947
|
-
return cachedResult;
|
|
1948
|
-
}
|
|
1949
|
-
cachedResult = computeMusicalTicks(params);
|
|
1950
|
-
cachedParams = {
|
|
1951
|
-
...params,
|
|
1952
|
-
meterEntries: params.meterEntries.map((e) => ({ ...e }))
|
|
1953
|
-
};
|
|
1954
|
-
return cachedResult;
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
// src/elements/daw-grid.ts
|
|
1958
|
-
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
1959
|
-
var DawGridElement = class extends LitElement9 {
|
|
2231
|
+
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
2232
|
+
var DawGridElement = class extends LitElement10 {
|
|
1960
2233
|
constructor() {
|
|
1961
2234
|
super(...arguments);
|
|
1962
2235
|
this.ticksPerPixel = 24;
|
|
@@ -1984,25 +2257,25 @@ var DawGridElement = class extends LitElement9 {
|
|
|
1984
2257
|
}
|
|
1985
2258
|
}
|
|
1986
2259
|
render() {
|
|
1987
|
-
if (!this._tickData) return
|
|
2260
|
+
if (!this._tickData) return html9``;
|
|
1988
2261
|
const totalWidth = this.length;
|
|
1989
2262
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1990
2263
|
const indices = getVisibleChunkIndices(
|
|
1991
2264
|
totalWidth,
|
|
1992
|
-
|
|
2265
|
+
MAX_CANVAS_WIDTH4,
|
|
1993
2266
|
this.visibleStart,
|
|
1994
2267
|
this.visibleEnd
|
|
1995
2268
|
);
|
|
1996
|
-
return
|
|
2269
|
+
return html9`
|
|
1997
2270
|
<div class="container" style="width: ${totalWidth}px; height: ${this.height}px;">
|
|
1998
2271
|
${indices.map((i) => {
|
|
1999
|
-
const width = Math.min(
|
|
2000
|
-
return
|
|
2272
|
+
const width = Math.min(MAX_CANVAS_WIDTH4, totalWidth - i * MAX_CANVAS_WIDTH4);
|
|
2273
|
+
return html9`
|
|
2001
2274
|
<canvas
|
|
2002
2275
|
data-index=${i}
|
|
2003
2276
|
width=${width * dpr}
|
|
2004
2277
|
height=${this.height * dpr}
|
|
2005
|
-
style="left: ${i *
|
|
2278
|
+
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.height}px;"
|
|
2006
2279
|
></canvas>
|
|
2007
2280
|
`;
|
|
2008
2281
|
})}
|
|
@@ -2026,8 +2299,8 @@ var DawGridElement = class extends LitElement9 {
|
|
|
2026
2299
|
const idx = Number(canvas.dataset.index);
|
|
2027
2300
|
const ctx = canvas.getContext("2d");
|
|
2028
2301
|
if (!ctx) continue;
|
|
2029
|
-
const chunkLeft = idx *
|
|
2030
|
-
const canvasWidth = Math.min(
|
|
2302
|
+
const chunkLeft = idx * MAX_CANVAS_WIDTH4;
|
|
2303
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, this.length - chunkLeft);
|
|
2031
2304
|
ctx.resetTransform();
|
|
2032
2305
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2033
2306
|
ctx.scale(dpr, dpr);
|
|
@@ -2058,7 +2331,7 @@ var DawGridElement = class extends LitElement9 {
|
|
|
2058
2331
|
}
|
|
2059
2332
|
}
|
|
2060
2333
|
};
|
|
2061
|
-
DawGridElement.styles =
|
|
2334
|
+
DawGridElement.styles = css8`
|
|
2062
2335
|
:host {
|
|
2063
2336
|
display: block;
|
|
2064
2337
|
position: absolute;
|
|
@@ -2076,33 +2349,33 @@ DawGridElement.styles = css7`
|
|
|
2076
2349
|
}
|
|
2077
2350
|
`;
|
|
2078
2351
|
__decorateClass([
|
|
2079
|
-
|
|
2352
|
+
property8({ type: Number, attribute: false })
|
|
2080
2353
|
], DawGridElement.prototype, "ticksPerPixel", 2);
|
|
2081
2354
|
__decorateClass([
|
|
2082
|
-
|
|
2355
|
+
property8({ attribute: false })
|
|
2083
2356
|
], DawGridElement.prototype, "meterEntries", 2);
|
|
2084
2357
|
__decorateClass([
|
|
2085
|
-
|
|
2358
|
+
property8({ type: Number, attribute: false })
|
|
2086
2359
|
], DawGridElement.prototype, "ppqn", 2);
|
|
2087
2360
|
__decorateClass([
|
|
2088
|
-
|
|
2361
|
+
property8({ type: Number, attribute: false })
|
|
2089
2362
|
], DawGridElement.prototype, "visibleStart", 2);
|
|
2090
2363
|
__decorateClass([
|
|
2091
|
-
|
|
2364
|
+
property8({ type: Number, attribute: false })
|
|
2092
2365
|
], DawGridElement.prototype, "visibleEnd", 2);
|
|
2093
2366
|
__decorateClass([
|
|
2094
|
-
|
|
2367
|
+
property8({ type: Number, attribute: false })
|
|
2095
2368
|
], DawGridElement.prototype, "length", 2);
|
|
2096
2369
|
__decorateClass([
|
|
2097
|
-
|
|
2370
|
+
property8({ type: Number, attribute: false })
|
|
2098
2371
|
], DawGridElement.prototype, "height", 2);
|
|
2099
2372
|
DawGridElement = __decorateClass([
|
|
2100
|
-
|
|
2373
|
+
customElement12("daw-grid")
|
|
2101
2374
|
], DawGridElement);
|
|
2102
2375
|
|
|
2103
2376
|
// src/styles/theme.ts
|
|
2104
|
-
import { css as
|
|
2105
|
-
var hostStyles =
|
|
2377
|
+
import { css as css9 } from "lit";
|
|
2378
|
+
var hostStyles = css9`
|
|
2106
2379
|
:host {
|
|
2107
2380
|
--daw-wave-color: #c49a6c;
|
|
2108
2381
|
--daw-progress-color: #63c75f;
|
|
@@ -2118,7 +2391,7 @@ var hostStyles = css8`
|
|
|
2118
2391
|
--daw-clip-header-text: #e0d4c8;
|
|
2119
2392
|
}
|
|
2120
2393
|
`;
|
|
2121
|
-
var clipStyles =
|
|
2394
|
+
var clipStyles = css9`
|
|
2122
2395
|
.clip-container {
|
|
2123
2396
|
position: absolute;
|
|
2124
2397
|
overflow: hidden;
|
|
@@ -2725,15 +2998,10 @@ var RecordingController = class {
|
|
|
2725
2998
|
import {
|
|
2726
2999
|
SpectrogramOrchestrator
|
|
2727
3000
|
} from "@dawcore/spectrogram";
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
minFrequency: 0,
|
|
2733
|
-
gainDb: 20,
|
|
2734
|
-
rangeDb: 80
|
|
2735
|
-
};
|
|
2736
|
-
var LIBRARY_DEFAULT_COLOR_MAP = "viridis";
|
|
3001
|
+
import {
|
|
3002
|
+
SPECTROGRAM_DEFAULTS as LIBRARY_DEFAULTS,
|
|
3003
|
+
DEFAULT_SPECTROGRAM_COLOR_MAP as LIBRARY_DEFAULT_COLOR_MAP
|
|
3004
|
+
} from "@waveform-playlist/core";
|
|
2737
3005
|
var SpectrogramController = class {
|
|
2738
3006
|
constructor(host, workerFactory) {
|
|
2739
3007
|
this.orchestrator = null;
|
|
@@ -2807,7 +3075,21 @@ var SpectrogramController = class {
|
|
|
2807
3075
|
const detail = e.detail;
|
|
2808
3076
|
this.host.dispatchEvent(
|
|
2809
3077
|
new CustomEvent("daw-spectrogram-ready", {
|
|
2810
|
-
detail,
|
|
3078
|
+
detail: { trackId: detail.trackId, generation: detail.generation },
|
|
3079
|
+
bubbles: true,
|
|
3080
|
+
composed: true
|
|
3081
|
+
})
|
|
3082
|
+
);
|
|
3083
|
+
});
|
|
3084
|
+
this.orchestrator.addEventListener("viewport-error", (e) => {
|
|
3085
|
+
const detail = e.detail;
|
|
3086
|
+
this.host.dispatchEvent(
|
|
3087
|
+
new CustomEvent("daw-spectrogram-error", {
|
|
3088
|
+
detail: {
|
|
3089
|
+
trackId: detail.trackId,
|
|
3090
|
+
generation: detail.generation,
|
|
3091
|
+
error: detail.error
|
|
3092
|
+
},
|
|
2811
3093
|
bubbles: true,
|
|
2812
3094
|
composed: true
|
|
2813
3095
|
})
|
|
@@ -2861,7 +3143,11 @@ var PointerHandler = class {
|
|
|
2861
3143
|
e.preventDefault();
|
|
2862
3144
|
this._timeline = this._host.shadowRoot?.querySelector(".timeline");
|
|
2863
3145
|
if (this._timeline) {
|
|
2864
|
-
|
|
3146
|
+
try {
|
|
3147
|
+
this._timeline.setPointerCapture(e.pointerId);
|
|
3148
|
+
} catch (err) {
|
|
3149
|
+
console.warn("[dawcore] setPointerCapture failed: " + String(err));
|
|
3150
|
+
}
|
|
2865
3151
|
const onMove = (me) => clipHandler.onPointerMove(me);
|
|
2866
3152
|
const onUp = (ue) => {
|
|
2867
3153
|
clipHandler.onPointerUp(ue);
|
|
@@ -2883,11 +3169,20 @@ var PointerHandler = class {
|
|
|
2883
3169
|
}
|
|
2884
3170
|
}
|
|
2885
3171
|
this._timeline = this._host.shadowRoot?.querySelector(".timeline");
|
|
2886
|
-
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
|
+
}
|
|
2887
3178
|
this._timelineRect = this._timeline.getBoundingClientRect();
|
|
2888
3179
|
this._dragStartPx = this._pxFromPointer(e);
|
|
2889
3180
|
this._isDragging = false;
|
|
2890
|
-
|
|
3181
|
+
try {
|
|
3182
|
+
this._timeline.setPointerCapture(e.pointerId);
|
|
3183
|
+
} catch (err) {
|
|
3184
|
+
console.warn("[dawcore] setPointerCapture failed: " + String(err));
|
|
3185
|
+
}
|
|
2891
3186
|
this._timeline.addEventListener("pointermove", this._onPointerMove);
|
|
2892
3187
|
this._timeline.addEventListener("pointerup", this._onPointerUp);
|
|
2893
3188
|
};
|
|
@@ -3819,9 +4114,143 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
3819
4114
|
}
|
|
3820
4115
|
}
|
|
3821
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
|
+
|
|
3822
4250
|
// src/elements/daw-editor.ts
|
|
4251
|
+
var RULER_HEIGHT = 30;
|
|
3823
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();";
|
|
3824
|
-
var DawEditorElement = class extends
|
|
4253
|
+
var DawEditorElement = class extends LitElement11 {
|
|
3825
4254
|
constructor() {
|
|
3826
4255
|
super(...arguments);
|
|
3827
4256
|
this._samplesPerPixel = 1024;
|
|
@@ -3880,13 +4309,21 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
3880
4309
|
v.scrollSelector = ".scroll-area";
|
|
3881
4310
|
return v;
|
|
3882
4311
|
})();
|
|
4312
|
+
this._scrollSync = (() => {
|
|
4313
|
+
const s = new ScrollSyncController(this);
|
|
4314
|
+
s.scrollSelector = ".scroll-area";
|
|
4315
|
+
return s;
|
|
4316
|
+
})();
|
|
3883
4317
|
/**
|
|
3884
4318
|
* Cache of the last ViewportState forwarded to the spectrogram controller.
|
|
3885
4319
|
* Lit's `updated()` fires on every reactive state change (`_isPlaying`,
|
|
3886
4320
|
* `_selectedTrackId`, etc.) — most of which don't affect the spectrogram
|
|
3887
4321
|
* viewport. Skip the cross-controller call when nothing changed.
|
|
3888
4322
|
*
|
|
3889
|
-
* The orchestrator dedupes too,
|
|
4323
|
+
* The orchestrator dedupes identical viewports too, so removing this cache
|
|
4324
|
+
* wouldn't change observable behavior — but it would push a fresh
|
|
4325
|
+
* `setViewport` call (with object allocation) into every Lit reactive
|
|
4326
|
+
* update for properties unrelated to the viewport.
|
|
3890
4327
|
*/
|
|
3891
4328
|
this._lastSpectrogramViewport = null;
|
|
3892
4329
|
// --- Track Events ---
|
|
@@ -4129,9 +4566,10 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
4129
4566
|
this._spectrogramController?.unregisterCanvas(canvasId);
|
|
4130
4567
|
}
|
|
4131
4568
|
/**
|
|
4132
|
-
*
|
|
4133
|
-
*
|
|
4134
|
-
*
|
|
4569
|
+
* Forward a clip's AudioBuffer to the spectrogram controller if the parent
|
|
4570
|
+
* track is in spectrogram render-mode. Eagerly creates the controller via
|
|
4571
|
+
* `_ensureSpectrogramController` so the audio data is queued for the first
|
|
4572
|
+
* render — even if no canvases have been registered yet.
|
|
4135
4573
|
*/
|
|
4136
4574
|
_maybeRegisterSpectrogramClipAudio(trackId, clip) {
|
|
4137
4575
|
const descriptor = this._tracks.get(trackId);
|
|
@@ -4422,6 +4860,13 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
4422
4860
|
}
|
|
4423
4861
|
}
|
|
4424
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();
|
|
4425
4870
|
if (this._spectrogramController) {
|
|
4426
4871
|
const vs = this._viewport.visibleStart;
|
|
4427
4872
|
const ve = this._viewport.visibleEnd;
|
|
@@ -5248,6 +5693,13 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5248
5693
|
}
|
|
5249
5694
|
const oldDesc = this._tracks.get(trackId);
|
|
5250
5695
|
if (!oldDesc) return;
|
|
5696
|
+
let normalizedRenderMode = partial.renderMode;
|
|
5697
|
+
if (normalizedRenderMode === "both") {
|
|
5698
|
+
console.warn(
|
|
5699
|
+
`[dawcore] render-mode="both" is not yet supported; falling back to 'spectrogram'`
|
|
5700
|
+
);
|
|
5701
|
+
normalizedRenderMode = "spectrogram";
|
|
5702
|
+
}
|
|
5251
5703
|
const newDesc = {
|
|
5252
5704
|
...oldDesc,
|
|
5253
5705
|
...partial.name !== void 0 && { name: partial.name },
|
|
@@ -5255,7 +5707,7 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5255
5707
|
...partial.pan !== void 0 && { pan: partial.pan },
|
|
5256
5708
|
...partial.muted !== void 0 && { muted: partial.muted },
|
|
5257
5709
|
...partial.soloed !== void 0 && { soloed: partial.soloed },
|
|
5258
|
-
...
|
|
5710
|
+
...normalizedRenderMode !== void 0 && { renderMode: normalizedRenderMode }
|
|
5259
5711
|
};
|
|
5260
5712
|
this._tracks = new Map(this._tracks).set(trackId, newDesc);
|
|
5261
5713
|
if (this._engine) {
|
|
@@ -5576,7 +6028,7 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5576
6028
|
const w = Math.floor(audibleSamples / renderSpp);
|
|
5577
6029
|
return rs.peaks.map((chPeaks, ch) => {
|
|
5578
6030
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
5579
|
-
return
|
|
6031
|
+
return html10`
|
|
5580
6032
|
<daw-waveform
|
|
5581
6033
|
data-recording-track=${trackId}
|
|
5582
6034
|
data-recording-channel=${ch}
|
|
@@ -5632,6 +6084,14 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5632
6084
|
_getPlayhead() {
|
|
5633
6085
|
return this.shadowRoot?.querySelector("daw-playhead");
|
|
5634
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
|
+
}
|
|
5635
6095
|
_getOrderedTracks() {
|
|
5636
6096
|
const domOrder = [...this.querySelectorAll("daw-track")].map(
|
|
5637
6097
|
(el) => el.trackId
|
|
@@ -5673,64 +6133,79 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5673
6133
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
5674
6134
|
};
|
|
5675
6135
|
});
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
style="height: ${t.trackHeight}px;"
|
|
5683
|
-
.trackId=${t.trackId}
|
|
5684
|
-
.trackName=${t.descriptor?.name ?? "Untitled"}
|
|
5685
|
-
.volume=${t.descriptor?.volume ?? 1}
|
|
5686
|
-
.pan=${t.descriptor?.pan ?? 0}
|
|
5687
|
-
.muted=${t.descriptor?.muted ?? false}
|
|
5688
|
-
.soloed=${t.descriptor?.soloed ?? false}
|
|
5689
|
-
></daw-track-controls>
|
|
5690
|
-
`
|
|
5691
|
-
)}
|
|
5692
|
-
</div>` : ""}
|
|
5693
|
-
<div class="scroll-area">
|
|
5694
|
-
<div
|
|
5695
|
-
class="timeline ${this._dragOver ? "drag-over" : ""}"
|
|
5696
|
-
style="width: ${this._totalWidth > 0 ? this._totalWidth + "px" : "100%"};"
|
|
5697
|
-
data-playing=${this._isPlaying}
|
|
5698
|
-
@pointerdown=${this._pointer.onPointerDown}
|
|
5699
|
-
@dragover=${this._onDragOver}
|
|
5700
|
-
@dragleave=${this._onDragLeave}
|
|
5701
|
-
@drop=${this._onDrop}
|
|
5702
|
-
>
|
|
5703
|
-
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ? html9`<daw-ruler
|
|
5704
|
-
.samplesPerPixel=${spp}
|
|
5705
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5706
|
-
.duration=${this._duration}
|
|
5707
|
-
.scaleMode=${this.scaleMode}
|
|
5708
|
-
.ticksPerPixel=${this.ticksPerPixel}
|
|
5709
|
-
.meterEntries=${this._meterEntries}
|
|
5710
|
-
.ppqn=${this.ppqn}
|
|
5711
|
-
.totalWidth=${this._totalWidth}
|
|
5712
|
-
></daw-ruler>` : ""}
|
|
5713
|
-
${this.scaleMode === "beats" ? html9`<daw-grid
|
|
5714
|
-
style="top: ${this.timescale ? 30 : 0}px;"
|
|
5715
|
-
.ticksPerPixel=${this.ticksPerPixel}
|
|
5716
|
-
.meterEntries=${this._meterEntries}
|
|
5717
|
-
.ppqn=${this.ppqn}
|
|
5718
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5719
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5720
|
-
.length=${this._totalWidth}
|
|
5721
|
-
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight + 1, 0) : this._emptyGridHeight}
|
|
5722
|
-
></daw-grid>` : ""}
|
|
5723
|
-
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ? html9`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
5724
|
-
<daw-playhead></daw-playhead>` : ""}
|
|
5725
|
-
${orderedTracks.map((t) => {
|
|
5726
|
-
const channelHeight = this.waveHeight;
|
|
5727
|
-
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}>
|
|
5728
6142
|
<div
|
|
5729
|
-
class="
|
|
5730
|
-
style="
|
|
5731
|
-
data-track-id=${t.trackId}
|
|
6143
|
+
class="ruler-content"
|
|
6144
|
+
style="width: ${this._totalWidth > 0 ? this._totalWidth + "px" : "100%"};"
|
|
5732
6145
|
>
|
|
5733
|
-
|
|
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) => {
|
|
5734
6209
|
const peakData = this._peaksData.get(clip.id);
|
|
5735
6210
|
let clipLeft;
|
|
5736
6211
|
let width;
|
|
@@ -5773,7 +6248,10 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5773
6248
|
const segEndSample = Math.round(segEndAudioSec * sr);
|
|
5774
6249
|
const totalPeaks = clip.durationSamples / baseScale;
|
|
5775
6250
|
clipSegments.push({
|
|
5776
|
-
peakStart: Math.max(
|
|
6251
|
+
peakStart: Math.max(
|
|
6252
|
+
0,
|
|
6253
|
+
(segStartSample - clip.offsetSamples) / baseScale
|
|
6254
|
+
),
|
|
5777
6255
|
peakEnd: Math.min(
|
|
5778
6256
|
totalPeaks,
|
|
5779
6257
|
(segEndSample - clip.offsetSamples) / baseScale
|
|
@@ -5787,78 +6265,79 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5787
6265
|
const channels = segmentChannels ?? peakData?.data ?? [new Int16Array(0)];
|
|
5788
6266
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
5789
6267
|
const chH = this.waveHeight;
|
|
5790
|
-
return
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
data-clip-id=${clip.id}
|
|
5798
|
-
data-track-id=${t.trackId}
|
|
5799
|
-
?data-interactive=${this.interactiveClips}
|
|
5800
|
-
>
|
|
5801
|
-
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
5802
|
-
</div>` : ""}
|
|
5803
|
-
${t.descriptor?.renderMode === "piano-roll" ? html9`<daw-piano-roll
|
|
5804
|
-
style="position:absolute;left:0;top:${hdrH}px;"
|
|
5805
|
-
.midiNotes=${clip.midiNotes ?? []}
|
|
5806
|
-
.length=${peakData?.length ?? width}
|
|
5807
|
-
.waveHeight=${chH * channels.length}
|
|
5808
|
-
.samplesPerPixel=${this._renderSpp}
|
|
5809
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5810
|
-
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
5811
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5812
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5813
|
-
.originX=${clipLeft}
|
|
5814
|
-
?selected=${t.trackId === this._selectedTrackId}
|
|
5815
|
-
></daw-piano-roll>` : t.descriptor?.renderMode === "spectrogram" ? channels.map(
|
|
5816
|
-
(_chPeaks, chIdx) => html9`<daw-spectrogram
|
|
5817
|
-
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;height:${chH}px;width:${peakData?.length ?? width}px;"
|
|
5818
|
-
.clipId=${clip.id}
|
|
5819
|
-
.trackId=${t.trackId}
|
|
5820
|
-
.channelIndex=${chIdx}
|
|
5821
|
-
.length=${peakData?.length ?? width}
|
|
5822
|
-
.waveHeight=${chH}
|
|
5823
|
-
.samplesPerPixel=${this._renderSpp}
|
|
5824
|
-
.sampleRate=${this.effectiveSampleRate}
|
|
5825
|
-
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
5826
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5827
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5828
|
-
.originX=${clipLeft}
|
|
5829
|
-
></daw-spectrogram>`
|
|
5830
|
-
) : channels.map(
|
|
5831
|
-
(chPeaks, chIdx) => html9` <daw-waveform
|
|
5832
|
-
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
5833
|
-
.peaks=${chPeaks}
|
|
5834
|
-
.length=${peakData?.length ?? width}
|
|
5835
|
-
.waveHeight=${chH}
|
|
5836
|
-
.barWidth=${this.barWidth}
|
|
5837
|
-
.barGap=${this.barGap}
|
|
5838
|
-
.visibleStart=${this._viewport.visibleStart}
|
|
5839
|
-
.visibleEnd=${this._viewport.visibleEnd}
|
|
5840
|
-
.originX=${clipLeft}
|
|
5841
|
-
.segments=${clipSegments}
|
|
5842
|
-
></daw-waveform>`
|
|
5843
|
-
)}
|
|
5844
|
-
${this.interactiveClips ? html9` <div
|
|
5845
|
-
class="clip-boundary"
|
|
5846
|
-
data-boundary-edge="left"
|
|
5847
|
-
data-clip-id=${clip.id}
|
|
5848
|
-
data-track-id=${t.trackId}
|
|
5849
|
-
></div>
|
|
5850
|
-
<div
|
|
5851
|
-
class="clip-boundary"
|
|
5852
|
-
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"
|
|
5853
6275
|
data-clip-id=${clip.id}
|
|
5854
6276
|
data-track-id=${t.trackId}
|
|
5855
|
-
|
|
5856
|
-
|
|
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>`;
|
|
5857
6335
|
})}
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
6336
|
+
${this._renderRecordingPreview(t.trackId, channelHeight)}
|
|
6337
|
+
</div>
|
|
6338
|
+
`;
|
|
5861
6339
|
})}
|
|
6340
|
+
</div>
|
|
5862
6341
|
</div>
|
|
5863
6342
|
</div>
|
|
5864
6343
|
<slot></slot>
|
|
@@ -5867,21 +6346,48 @@ var DawEditorElement = class extends LitElement10 {
|
|
|
5867
6346
|
};
|
|
5868
6347
|
DawEditorElement.styles = [
|
|
5869
6348
|
hostStyles,
|
|
5870
|
-
|
|
6349
|
+
css10`
|
|
5871
6350
|
:host {
|
|
5872
6351
|
display: flex;
|
|
6352
|
+
flex-direction: column;
|
|
5873
6353
|
position: relative;
|
|
5874
6354
|
background: var(--daw-background, #1a1a2e);
|
|
5875
6355
|
overflow: hidden;
|
|
5876
6356
|
}
|
|
5877
|
-
.
|
|
6357
|
+
.header-row {
|
|
6358
|
+
display: flex;
|
|
6359
|
+
flex-shrink: 0;
|
|
6360
|
+
}
|
|
6361
|
+
.ruler-gap {
|
|
5878
6362
|
flex-shrink: 0;
|
|
5879
6363
|
width: var(--daw-controls-width, 180px);
|
|
5880
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 {
|
|
6380
|
+
flex-shrink: 0;
|
|
6381
|
+
width: var(--daw-controls-width, 180px);
|
|
6382
|
+
overflow: hidden;
|
|
6383
|
+
}
|
|
6384
|
+
.controls-column {
|
|
6385
|
+
will-change: transform;
|
|
6386
|
+
}
|
|
5881
6387
|
.scroll-area {
|
|
5882
6388
|
flex: 1;
|
|
5883
|
-
overflow
|
|
5884
|
-
overflow-
|
|
6389
|
+
overflow: auto;
|
|
6390
|
+
overflow-anchor: none;
|
|
5885
6391
|
min-height: var(--daw-min-height, 200px);
|
|
5886
6392
|
}
|
|
5887
6393
|
.timeline {
|
|
@@ -5891,6 +6397,7 @@ DawEditorElement.styles = [
|
|
|
5891
6397
|
}
|
|
5892
6398
|
.track-row {
|
|
5893
6399
|
position: relative;
|
|
6400
|
+
box-sizing: border-box;
|
|
5894
6401
|
background: var(--daw-track-background, #16213e);
|
|
5895
6402
|
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
5896
6403
|
}
|
|
@@ -5915,70 +6422,70 @@ DawEditorElement.styles = [
|
|
|
5915
6422
|
];
|
|
5916
6423
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
5917
6424
|
__decorateClass([
|
|
5918
|
-
|
|
6425
|
+
property9({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
5919
6426
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
5920
6427
|
__decorateClass([
|
|
5921
|
-
|
|
6428
|
+
property9({ type: Number, attribute: "wave-height" })
|
|
5922
6429
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
5923
6430
|
__decorateClass([
|
|
5924
|
-
|
|
6431
|
+
property9({ type: Boolean })
|
|
5925
6432
|
], DawEditorElement.prototype, "timescale", 2);
|
|
5926
6433
|
__decorateClass([
|
|
5927
|
-
|
|
6434
|
+
property9({ type: Boolean })
|
|
5928
6435
|
], DawEditorElement.prototype, "mono", 2);
|
|
5929
6436
|
__decorateClass([
|
|
5930
|
-
|
|
6437
|
+
property9({ type: Number, attribute: "bar-width" })
|
|
5931
6438
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
5932
6439
|
__decorateClass([
|
|
5933
|
-
|
|
6440
|
+
property9({ type: Number, attribute: "bar-gap" })
|
|
5934
6441
|
], DawEditorElement.prototype, "barGap", 2);
|
|
5935
6442
|
__decorateClass([
|
|
5936
|
-
|
|
6443
|
+
property9({ type: Boolean, attribute: "file-drop" })
|
|
5937
6444
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
5938
6445
|
__decorateClass([
|
|
5939
|
-
|
|
6446
|
+
property9({ type: Boolean, attribute: "clip-headers" })
|
|
5940
6447
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
5941
6448
|
__decorateClass([
|
|
5942
|
-
|
|
6449
|
+
property9({ type: Number, attribute: "clip-header-height" })
|
|
5943
6450
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
5944
6451
|
__decorateClass([
|
|
5945
|
-
|
|
6452
|
+
property9({ type: Boolean, attribute: "interactive-clips" })
|
|
5946
6453
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
5947
6454
|
__decorateClass([
|
|
5948
|
-
|
|
6455
|
+
property9({ type: Boolean, attribute: "indefinite-playback" })
|
|
5949
6456
|
], DawEditorElement.prototype, "indefinitePlayback", 2);
|
|
5950
6457
|
__decorateClass([
|
|
5951
|
-
|
|
6458
|
+
property9({ attribute: false, noAccessor: true })
|
|
5952
6459
|
], DawEditorElement.prototype, "spectrogramConfig", 1);
|
|
5953
6460
|
__decorateClass([
|
|
5954
|
-
|
|
6461
|
+
property9({ attribute: false, noAccessor: true })
|
|
5955
6462
|
], DawEditorElement.prototype, "spectrogramColorMap", 1);
|
|
5956
6463
|
__decorateClass([
|
|
5957
|
-
|
|
6464
|
+
property9({ type: String, attribute: "scale-mode" })
|
|
5958
6465
|
], DawEditorElement.prototype, "scaleMode", 2);
|
|
5959
6466
|
__decorateClass([
|
|
5960
|
-
|
|
6467
|
+
property9({ type: Number, attribute: "ticks-per-pixel", noAccessor: true })
|
|
5961
6468
|
], DawEditorElement.prototype, "ticksPerPixel", 1);
|
|
5962
6469
|
__decorateClass([
|
|
5963
|
-
|
|
6470
|
+
property9({ type: Number, noAccessor: true })
|
|
5964
6471
|
], DawEditorElement.prototype, "bpm", 1);
|
|
5965
6472
|
__decorateClass([
|
|
5966
|
-
|
|
6473
|
+
property9({ attribute: false })
|
|
5967
6474
|
], DawEditorElement.prototype, "timeSignature", 2);
|
|
5968
6475
|
__decorateClass([
|
|
5969
|
-
|
|
6476
|
+
property9({ attribute: false })
|
|
5970
6477
|
], DawEditorElement.prototype, "meterEntries", 2);
|
|
5971
6478
|
__decorateClass([
|
|
5972
|
-
|
|
6479
|
+
property9({ type: Number, noAccessor: true })
|
|
5973
6480
|
], DawEditorElement.prototype, "ppqn", 1);
|
|
5974
6481
|
__decorateClass([
|
|
5975
|
-
|
|
6482
|
+
property9({ type: String, attribute: "snap-to" })
|
|
5976
6483
|
], DawEditorElement.prototype, "snapTo", 2);
|
|
5977
6484
|
__decorateClass([
|
|
5978
|
-
|
|
6485
|
+
property9({ attribute: false })
|
|
5979
6486
|
], DawEditorElement.prototype, "secondsToTicks", 2);
|
|
5980
6487
|
__decorateClass([
|
|
5981
|
-
|
|
6488
|
+
property9({ attribute: false })
|
|
5982
6489
|
], DawEditorElement.prototype, "ticksToSeconds", 2);
|
|
5983
6490
|
__decorateClass([
|
|
5984
6491
|
state3()
|
|
@@ -6002,246 +6509,15 @@ __decorateClass([
|
|
|
6002
6509
|
state3()
|
|
6003
6510
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
6004
6511
|
__decorateClass([
|
|
6005
|
-
|
|
6512
|
+
property9({ attribute: false })
|
|
6006
6513
|
], DawEditorElement.prototype, "adapter", 1);
|
|
6007
6514
|
__decorateClass([
|
|
6008
|
-
|
|
6515
|
+
property9({ attribute: "eager-resume" })
|
|
6009
6516
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
6010
6517
|
DawEditorElement = __decorateClass([
|
|
6011
|
-
|
|
6518
|
+
customElement13("daw-editor")
|
|
6012
6519
|
], DawEditorElement);
|
|
6013
6520
|
|
|
6014
|
-
// src/elements/daw-ruler.ts
|
|
6015
|
-
import { LitElement as LitElement11, html as html10, css as css10 } from "lit";
|
|
6016
|
-
import { customElement as customElement13, property as property9 } from "lit/decorators.js";
|
|
6017
|
-
|
|
6018
|
-
// src/utils/time-format.ts
|
|
6019
|
-
function formatTime(milliseconds) {
|
|
6020
|
-
const seconds = Math.floor(milliseconds / 1e3);
|
|
6021
|
-
const s = seconds % 60;
|
|
6022
|
-
const m = (seconds - s) / 60;
|
|
6023
|
-
return `${m}:${String(s).padStart(2, "0")}`;
|
|
6024
|
-
}
|
|
6025
|
-
|
|
6026
|
-
// src/utils/smart-scale.ts
|
|
6027
|
-
var timeinfo = /* @__PURE__ */ new Map([
|
|
6028
|
-
[700, { marker: 1e3, bigStep: 500, smallStep: 100 }],
|
|
6029
|
-
[1500, { marker: 2e3, bigStep: 1e3, smallStep: 200 }],
|
|
6030
|
-
[2500, { marker: 2e3, bigStep: 1e3, smallStep: 500 }],
|
|
6031
|
-
[5e3, { marker: 5e3, bigStep: 1e3, smallStep: 500 }],
|
|
6032
|
-
[1e4, { marker: 1e4, bigStep: 5e3, smallStep: 1e3 }],
|
|
6033
|
-
[12e3, { marker: 15e3, bigStep: 5e3, smallStep: 1e3 }],
|
|
6034
|
-
[Infinity, { marker: 3e4, bigStep: 1e4, smallStep: 5e3 }]
|
|
6035
|
-
]);
|
|
6036
|
-
function getScaleInfo(samplesPerPixel) {
|
|
6037
|
-
for (const [resolution, config] of timeinfo) {
|
|
6038
|
-
if (samplesPerPixel < resolution) {
|
|
6039
|
-
return config;
|
|
6040
|
-
}
|
|
6041
|
-
}
|
|
6042
|
-
return { marker: 3e4, bigStep: 1e4, smallStep: 5e3 };
|
|
6043
|
-
}
|
|
6044
|
-
function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight) {
|
|
6045
|
-
const widthX = Math.ceil(duration * sampleRate / samplesPerPixel);
|
|
6046
|
-
const config = getScaleInfo(samplesPerPixel);
|
|
6047
|
-
const { marker, bigStep, smallStep } = config;
|
|
6048
|
-
const canvasInfo = /* @__PURE__ */ new Map();
|
|
6049
|
-
const labels = [];
|
|
6050
|
-
const pixPerSec = sampleRate / samplesPerPixel;
|
|
6051
|
-
for (let counter = 0; ; counter += smallStep) {
|
|
6052
|
-
const pix = Math.floor(counter / 1e3 * pixPerSec);
|
|
6053
|
-
if (pix >= widthX) break;
|
|
6054
|
-
if (counter % marker === 0) {
|
|
6055
|
-
canvasInfo.set(pix, rulerHeight);
|
|
6056
|
-
labels.push({ pix, text: formatTime(counter) });
|
|
6057
|
-
} else if (counter % bigStep === 0) {
|
|
6058
|
-
canvasInfo.set(pix, Math.floor(rulerHeight / 2));
|
|
6059
|
-
} else if (counter % smallStep === 0) {
|
|
6060
|
-
canvasInfo.set(pix, Math.floor(rulerHeight / 5));
|
|
6061
|
-
}
|
|
6062
|
-
}
|
|
6063
|
-
return { widthX, canvasInfo, labels };
|
|
6064
|
-
}
|
|
6065
|
-
|
|
6066
|
-
// src/elements/daw-ruler.ts
|
|
6067
|
-
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
6068
|
-
var DawRulerElement = class extends LitElement11 {
|
|
6069
|
-
constructor() {
|
|
6070
|
-
super(...arguments);
|
|
6071
|
-
this.samplesPerPixel = 1024;
|
|
6072
|
-
this.sampleRate = 48e3;
|
|
6073
|
-
this.duration = 0;
|
|
6074
|
-
this.rulerHeight = 30;
|
|
6075
|
-
this.scaleMode = "temporal";
|
|
6076
|
-
this.ticksPerPixel = 4;
|
|
6077
|
-
this.meterEntries = [
|
|
6078
|
-
{ tick: 0, numerator: 4, denominator: 4 }
|
|
6079
|
-
];
|
|
6080
|
-
this.ppqn = 960;
|
|
6081
|
-
this.totalWidth = 0;
|
|
6082
|
-
this._tickData = null;
|
|
6083
|
-
this._musicalTickData = null;
|
|
6084
|
-
}
|
|
6085
|
-
willUpdate() {
|
|
6086
|
-
if (this.scaleMode === "beats" && this.totalWidth > 0) {
|
|
6087
|
-
this._musicalTickData = getCachedMusicalTicks({
|
|
6088
|
-
meterEntries: this.meterEntries,
|
|
6089
|
-
ticksPerPixel: this.ticksPerPixel,
|
|
6090
|
-
startPixel: 0,
|
|
6091
|
-
endPixel: this.totalWidth,
|
|
6092
|
-
ppqn: this.ppqn
|
|
6093
|
-
});
|
|
6094
|
-
this._tickData = null;
|
|
6095
|
-
} else if (this.duration > 0 || this.totalWidth > 0) {
|
|
6096
|
-
const widthDerivedDuration = this.totalWidth * this.samplesPerPixel / this.sampleRate;
|
|
6097
|
-
const effectiveDuration = Math.max(this.duration, widthDerivedDuration);
|
|
6098
|
-
this._musicalTickData = null;
|
|
6099
|
-
this._tickData = computeTemporalTicks(
|
|
6100
|
-
this.samplesPerPixel,
|
|
6101
|
-
this.sampleRate,
|
|
6102
|
-
effectiveDuration,
|
|
6103
|
-
this.rulerHeight
|
|
6104
|
-
);
|
|
6105
|
-
} else {
|
|
6106
|
-
this._musicalTickData = null;
|
|
6107
|
-
this._tickData = null;
|
|
6108
|
-
}
|
|
6109
|
-
}
|
|
6110
|
-
render() {
|
|
6111
|
-
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
6112
|
-
if (widthX <= 0) return html10``;
|
|
6113
|
-
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH4);
|
|
6114
|
-
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
6115
|
-
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
6116
|
-
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
6117
|
-
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
6118
|
-
return html10`
|
|
6119
|
-
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
6120
|
-
${indices.map((i) => {
|
|
6121
|
-
const width = Math.min(MAX_CANVAS_WIDTH4, widthX - i * MAX_CANVAS_WIDTH4);
|
|
6122
|
-
return html10`
|
|
6123
|
-
<canvas
|
|
6124
|
-
data-index=${i}
|
|
6125
|
-
width=${width * dpr}
|
|
6126
|
-
height=${this.rulerHeight * dpr}
|
|
6127
|
-
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
6128
|
-
></canvas>
|
|
6129
|
-
`;
|
|
6130
|
-
})}
|
|
6131
|
-
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
6132
|
-
(t) => html10`<span
|
|
6133
|
-
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
6134
|
-
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
6135
|
-
>${t.label}</span
|
|
6136
|
-
>`
|
|
6137
|
-
) : temporalLabels.map(
|
|
6138
|
-
({ pix, text }) => html10`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
6139
|
-
)}
|
|
6140
|
-
</div>
|
|
6141
|
-
`;
|
|
6142
|
-
}
|
|
6143
|
-
updated() {
|
|
6144
|
-
this._drawTicks();
|
|
6145
|
-
}
|
|
6146
|
-
_drawTicks() {
|
|
6147
|
-
const canvases = this.shadowRoot?.querySelectorAll("canvas");
|
|
6148
|
-
if (!canvases) return;
|
|
6149
|
-
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
6150
|
-
const rulerColor = getComputedStyle(this).getPropertyValue("--daw-ruler-color").trim() || "#c49a6c";
|
|
6151
|
-
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
6152
|
-
for (const canvas of canvases) {
|
|
6153
|
-
const idx = Number(canvas.dataset.index);
|
|
6154
|
-
const ctx = canvas.getContext("2d");
|
|
6155
|
-
if (!ctx) continue;
|
|
6156
|
-
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, widthX - idx * MAX_CANVAS_WIDTH4);
|
|
6157
|
-
const globalOffset = idx * MAX_CANVAS_WIDTH4;
|
|
6158
|
-
ctx.resetTransform();
|
|
6159
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6160
|
-
ctx.scale(dpr, dpr);
|
|
6161
|
-
ctx.strokeStyle = rulerColor;
|
|
6162
|
-
ctx.lineWidth = 1;
|
|
6163
|
-
if (this.scaleMode === "beats" && this._musicalTickData) {
|
|
6164
|
-
const h = this.rulerHeight;
|
|
6165
|
-
for (const tick of this._musicalTickData.ticks) {
|
|
6166
|
-
const localX = tick.pixel - globalOffset;
|
|
6167
|
-
if (localX < 0 || localX >= canvasWidth) continue;
|
|
6168
|
-
const tickH = tick.type === "major" ? h * 0.6 : tick.type === "minor" ? h * 0.35 : h * 0.15;
|
|
6169
|
-
ctx.globalAlpha = tick.type === "major" ? 1 : 0.5;
|
|
6170
|
-
ctx.beginPath();
|
|
6171
|
-
ctx.moveTo(localX + 0.5, h);
|
|
6172
|
-
ctx.lineTo(localX + 0.5, h - tickH);
|
|
6173
|
-
ctx.stroke();
|
|
6174
|
-
}
|
|
6175
|
-
ctx.globalAlpha = 1;
|
|
6176
|
-
} else if (this._tickData) {
|
|
6177
|
-
for (const [pix, height] of this._tickData.canvasInfo) {
|
|
6178
|
-
const localX = pix - globalOffset;
|
|
6179
|
-
if (localX < 0 || localX >= canvasWidth) continue;
|
|
6180
|
-
ctx.beginPath();
|
|
6181
|
-
ctx.moveTo(localX + 0.5, this.rulerHeight);
|
|
6182
|
-
ctx.lineTo(localX + 0.5, this.rulerHeight - height);
|
|
6183
|
-
ctx.stroke();
|
|
6184
|
-
}
|
|
6185
|
-
}
|
|
6186
|
-
}
|
|
6187
|
-
}
|
|
6188
|
-
};
|
|
6189
|
-
DawRulerElement.styles = css10`
|
|
6190
|
-
:host {
|
|
6191
|
-
display: block;
|
|
6192
|
-
position: relative;
|
|
6193
|
-
background: var(--daw-ruler-background, #0f0f1a);
|
|
6194
|
-
}
|
|
6195
|
-
.container {
|
|
6196
|
-
position: relative;
|
|
6197
|
-
}
|
|
6198
|
-
canvas {
|
|
6199
|
-
position: absolute;
|
|
6200
|
-
top: 0;
|
|
6201
|
-
}
|
|
6202
|
-
.label {
|
|
6203
|
-
position: absolute;
|
|
6204
|
-
font-size: 0.7rem;
|
|
6205
|
-
line-height: 1;
|
|
6206
|
-
white-space: nowrap;
|
|
6207
|
-
color: var(--daw-ruler-color, #c49a6c);
|
|
6208
|
-
top: 1px;
|
|
6209
|
-
}
|
|
6210
|
-
.label.centered {
|
|
6211
|
-
transform: translateX(-50%);
|
|
6212
|
-
}
|
|
6213
|
-
`;
|
|
6214
|
-
__decorateClass([
|
|
6215
|
-
property9({ type: Number, attribute: false })
|
|
6216
|
-
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
6217
|
-
__decorateClass([
|
|
6218
|
-
property9({ type: Number, attribute: false })
|
|
6219
|
-
], DawRulerElement.prototype, "sampleRate", 2);
|
|
6220
|
-
__decorateClass([
|
|
6221
|
-
property9({ type: Number, attribute: false })
|
|
6222
|
-
], DawRulerElement.prototype, "duration", 2);
|
|
6223
|
-
__decorateClass([
|
|
6224
|
-
property9({ type: Number, attribute: false })
|
|
6225
|
-
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
6226
|
-
__decorateClass([
|
|
6227
|
-
property9({ type: String, attribute: false })
|
|
6228
|
-
], DawRulerElement.prototype, "scaleMode", 2);
|
|
6229
|
-
__decorateClass([
|
|
6230
|
-
property9({ type: Number, attribute: false })
|
|
6231
|
-
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
6232
|
-
__decorateClass([
|
|
6233
|
-
property9({ attribute: false })
|
|
6234
|
-
], DawRulerElement.prototype, "meterEntries", 2);
|
|
6235
|
-
__decorateClass([
|
|
6236
|
-
property9({ type: Number, attribute: false })
|
|
6237
|
-
], DawRulerElement.prototype, "ppqn", 2);
|
|
6238
|
-
__decorateClass([
|
|
6239
|
-
property9({ type: Number, attribute: false })
|
|
6240
|
-
], DawRulerElement.prototype, "totalWidth", 2);
|
|
6241
|
-
DawRulerElement = __decorateClass([
|
|
6242
|
-
customElement13("daw-ruler")
|
|
6243
|
-
], DawRulerElement);
|
|
6244
|
-
|
|
6245
6521
|
// src/elements/daw-selection.ts
|
|
6246
6522
|
import { LitElement as LitElement12, html as html11, css as css11 } from "lit";
|
|
6247
6523
|
import { customElement as customElement14, property as property10 } from "lit/decorators.js";
|
|
@@ -6552,6 +6828,7 @@ var DawSpectrogramElement = class extends LitElement14 {
|
|
|
6552
6828
|
this.originX = 0;
|
|
6553
6829
|
this._canvases = [];
|
|
6554
6830
|
this._registeredCanvasIds = [];
|
|
6831
|
+
this._warnedNoHost = false;
|
|
6555
6832
|
}
|
|
6556
6833
|
get samplesPerPixel() {
|
|
6557
6834
|
return this._samplesPerPixel;
|
|
@@ -6618,7 +6895,15 @@ var DawSpectrogramElement = class extends LitElement14 {
|
|
|
6618
6895
|
}
|
|
6619
6896
|
_registerCanvases() {
|
|
6620
6897
|
const editor = this._findHostEditor();
|
|
6621
|
-
if (!editor || typeof editor._spectrogramRegisterCanvas !== "function")
|
|
6898
|
+
if (!editor || typeof editor._spectrogramRegisterCanvas !== "function") {
|
|
6899
|
+
if (!this._warnedNoHost) {
|
|
6900
|
+
this._warnedNoHost = true;
|
|
6901
|
+
console.warn(
|
|
6902
|
+
"[dawcore] <daw-spectrogram> (clip " + this.clipId + ") could not find host <daw-editor>. Canvases will not render. Ensure the element is mounted inside a <daw-editor>."
|
|
6903
|
+
);
|
|
6904
|
+
}
|
|
6905
|
+
return;
|
|
6906
|
+
}
|
|
6622
6907
|
for (let i = 0; i < this._canvases.length; i++) {
|
|
6623
6908
|
const canvas = this._canvases[i];
|
|
6624
6909
|
const canvasId = this.clipId + "-ch" + this.channelIndex + "-chunk" + i;
|