@dawcore/components 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +220 -85
- package/dist/index.d.ts +220 -85
- package/dist/index.js +741 -199
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +730 -189
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -26,11 +26,48 @@ var DawClipElement = class extends LitElement {
|
|
|
26
26
|
this.fadeIn = 0;
|
|
27
27
|
this.fadeOut = 0;
|
|
28
28
|
this.fadeType = "linear";
|
|
29
|
+
this.midiNotes = null;
|
|
30
|
+
this._midiChannel = null;
|
|
31
|
+
this._midiProgram = null;
|
|
29
32
|
this.clipId = crypto.randomUUID();
|
|
30
33
|
// Removal is detected by the editor's MutationObserver — detached elements
|
|
31
34
|
// cannot bubble events to ancestors.
|
|
32
35
|
this._hasRendered = false;
|
|
33
36
|
}
|
|
37
|
+
get midiChannel() {
|
|
38
|
+
return this._midiChannel;
|
|
39
|
+
}
|
|
40
|
+
set midiChannel(value) {
|
|
41
|
+
const old = this._midiChannel;
|
|
42
|
+
if (value === null) {
|
|
43
|
+
this._midiChannel = null;
|
|
44
|
+
this.requestUpdate("midiChannel", old);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 15) {
|
|
48
|
+
console.warn("[dawcore] daw-clip midi-channel " + value + " is out of range 0-15 \u2014 ignored");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this._midiChannel = value;
|
|
52
|
+
this.requestUpdate("midiChannel", old);
|
|
53
|
+
}
|
|
54
|
+
get midiProgram() {
|
|
55
|
+
return this._midiProgram;
|
|
56
|
+
}
|
|
57
|
+
set midiProgram(value) {
|
|
58
|
+
const old = this._midiProgram;
|
|
59
|
+
if (value === null) {
|
|
60
|
+
this._midiProgram = null;
|
|
61
|
+
this.requestUpdate("midiProgram", old);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 127) {
|
|
65
|
+
console.warn("[dawcore] daw-clip midi-program " + value + " is out of range 0-127 \u2014 ignored");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this._midiProgram = value;
|
|
69
|
+
this.requestUpdate("midiProgram", old);
|
|
70
|
+
}
|
|
34
71
|
// Light DOM — no visual rendering, just a data container
|
|
35
72
|
createRenderRoot() {
|
|
36
73
|
return this;
|
|
@@ -62,7 +99,10 @@ var DawClipElement = class extends LitElement {
|
|
|
62
99
|
"name",
|
|
63
100
|
"fadeIn",
|
|
64
101
|
"fadeOut",
|
|
65
|
-
"fadeType"
|
|
102
|
+
"fadeType",
|
|
103
|
+
"midiNotes",
|
|
104
|
+
"midiChannel",
|
|
105
|
+
"midiProgram"
|
|
66
106
|
];
|
|
67
107
|
if (clipProps.some((p) => changed.has(p))) {
|
|
68
108
|
const trackEl = this.closest("daw-track");
|
|
@@ -109,6 +149,15 @@ __decorateClass([
|
|
|
109
149
|
__decorateClass([
|
|
110
150
|
property({ attribute: "fade-type" })
|
|
111
151
|
], DawClipElement.prototype, "fadeType", 2);
|
|
152
|
+
__decorateClass([
|
|
153
|
+
property({ attribute: false })
|
|
154
|
+
], DawClipElement.prototype, "midiNotes", 2);
|
|
155
|
+
__decorateClass([
|
|
156
|
+
property({ type: Number, attribute: "midi-channel", noAccessor: true })
|
|
157
|
+
], DawClipElement.prototype, "midiChannel", 1);
|
|
158
|
+
__decorateClass([
|
|
159
|
+
property({ type: Number, attribute: "midi-program", noAccessor: true })
|
|
160
|
+
], DawClipElement.prototype, "midiProgram", 1);
|
|
112
161
|
DawClipElement = __decorateClass([
|
|
113
162
|
customElement("daw-clip")
|
|
114
163
|
], DawClipElement);
|
|
@@ -125,6 +174,7 @@ var DawTrackElement = class extends LitElement2 {
|
|
|
125
174
|
this.pan = 0;
|
|
126
175
|
this.muted = false;
|
|
127
176
|
this.soloed = false;
|
|
177
|
+
this.renderMode = "waveform";
|
|
128
178
|
this.trackId = crypto.randomUUID();
|
|
129
179
|
// Track removal is detected by the editor's MutationObserver,
|
|
130
180
|
// not by dispatching from disconnectedCallback (detached elements
|
|
@@ -152,7 +202,7 @@ var DawTrackElement = class extends LitElement2 {
|
|
|
152
202
|
this._hasRendered = true;
|
|
153
203
|
return;
|
|
154
204
|
}
|
|
155
|
-
const trackProps = ["volume", "pan", "muted", "soloed", "src", "name"];
|
|
205
|
+
const trackProps = ["volume", "pan", "muted", "soloed", "src", "name", "renderMode"];
|
|
156
206
|
const hasTrackChange = trackProps.some((p) => changed.has(p));
|
|
157
207
|
if (hasTrackChange) {
|
|
158
208
|
this.dispatchEvent(
|
|
@@ -183,6 +233,9 @@ __decorateClass([
|
|
|
183
233
|
__decorateClass([
|
|
184
234
|
property2({ type: Boolean })
|
|
185
235
|
], DawTrackElement.prototype, "soloed", 2);
|
|
236
|
+
__decorateClass([
|
|
237
|
+
property2({ attribute: "render-mode" })
|
|
238
|
+
], DawTrackElement.prototype, "renderMode", 2);
|
|
186
239
|
DawTrackElement = __decorateClass([
|
|
187
240
|
customElement2("daw-track")
|
|
188
241
|
], DawTrackElement);
|
|
@@ -532,9 +585,229 @@ DawWaveformElement = __decorateClass([
|
|
|
532
585
|
customElement3("daw-waveform")
|
|
533
586
|
], DawWaveformElement);
|
|
534
587
|
|
|
535
|
-
// src/elements/daw-
|
|
588
|
+
// src/elements/daw-piano-roll.ts
|
|
536
589
|
import { LitElement as LitElement4, html as html2, css as css2 } from "lit";
|
|
537
|
-
import { customElement as customElement4 } from "lit/decorators.js";
|
|
590
|
+
import { customElement as customElement4, property as property4 } from "lit/decorators.js";
|
|
591
|
+
var MAX_CANVAS_WIDTH2 = 1e3;
|
|
592
|
+
var LAYOUT_PROPS2 = /* @__PURE__ */ new Set([
|
|
593
|
+
"length",
|
|
594
|
+
"waveHeight",
|
|
595
|
+
"samplesPerPixel",
|
|
596
|
+
"sampleRate",
|
|
597
|
+
"clipOffsetSeconds",
|
|
598
|
+
"midiNotes",
|
|
599
|
+
"selected"
|
|
600
|
+
]);
|
|
601
|
+
var DawPianoRollElement = class extends LitElement4 {
|
|
602
|
+
constructor() {
|
|
603
|
+
super(...arguments);
|
|
604
|
+
this.midiNotes = [];
|
|
605
|
+
this.length = 0;
|
|
606
|
+
this.waveHeight = 128;
|
|
607
|
+
this._samplesPerPixel = 1024;
|
|
608
|
+
this._sampleRate = 48e3;
|
|
609
|
+
this.clipOffsetSeconds = 0;
|
|
610
|
+
this.visibleStart = -Infinity;
|
|
611
|
+
this.visibleEnd = Infinity;
|
|
612
|
+
this.originX = 0;
|
|
613
|
+
this.selected = false;
|
|
614
|
+
this._rafHandle = null;
|
|
615
|
+
}
|
|
616
|
+
get samplesPerPixel() {
|
|
617
|
+
return this._samplesPerPixel;
|
|
618
|
+
}
|
|
619
|
+
set samplesPerPixel(value) {
|
|
620
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
621
|
+
console.warn("[dawcore] daw-piano-roll samplesPerPixel " + value + " is invalid \u2014 ignored");
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const old = this._samplesPerPixel;
|
|
625
|
+
this._samplesPerPixel = value;
|
|
626
|
+
this.requestUpdate("samplesPerPixel", old);
|
|
627
|
+
}
|
|
628
|
+
get sampleRate() {
|
|
629
|
+
return this._sampleRate;
|
|
630
|
+
}
|
|
631
|
+
set sampleRate(value) {
|
|
632
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
633
|
+
console.warn("[dawcore] daw-piano-roll sampleRate " + value + " is invalid \u2014 ignored");
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const old = this._sampleRate;
|
|
637
|
+
this._sampleRate = value;
|
|
638
|
+
this.requestUpdate("sampleRate", old);
|
|
639
|
+
}
|
|
640
|
+
_scheduleDraw() {
|
|
641
|
+
if (this._rafHandle !== null) return;
|
|
642
|
+
this._rafHandle = requestAnimationFrame(() => {
|
|
643
|
+
this._rafHandle = null;
|
|
644
|
+
this._draw();
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
willUpdate(_changed) {
|
|
648
|
+
this._scheduleDraw();
|
|
649
|
+
}
|
|
650
|
+
updated(changedProperties) {
|
|
651
|
+
const needsFullDraw = [...changedProperties.keys()].some((key) => LAYOUT_PROPS2.has(key));
|
|
652
|
+
if (needsFullDraw) return;
|
|
653
|
+
if (changedProperties.has("visibleStart") || changedProperties.has("visibleEnd") || changedProperties.has("originX")) {
|
|
654
|
+
this._scheduleDraw();
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
_getPitchRange() {
|
|
658
|
+
if (this.midiNotes.length === 0) return { minMidi: 0, maxMidi: 127 };
|
|
659
|
+
let min = 127;
|
|
660
|
+
let max = 0;
|
|
661
|
+
for (const note of this.midiNotes) {
|
|
662
|
+
if (note.midi < min) min = note.midi;
|
|
663
|
+
if (note.midi > max) max = note.midi;
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
minMidi: Math.max(0, min - 1),
|
|
667
|
+
maxMidi: Math.min(127, max + 1)
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
_getNoteColor() {
|
|
671
|
+
const cs = getComputedStyle(this);
|
|
672
|
+
const note = cs.getPropertyValue("--daw-piano-roll-note-color").trim() || "#2a7070";
|
|
673
|
+
const selectedColor = cs.getPropertyValue("--daw-piano-roll-selected-note-color").trim() || "#3d9e9e";
|
|
674
|
+
return this.selected ? selectedColor : note;
|
|
675
|
+
}
|
|
676
|
+
_draw() {
|
|
677
|
+
if (!this.shadowRoot) return;
|
|
678
|
+
const canvases = this.shadowRoot.querySelectorAll("canvas");
|
|
679
|
+
if (canvases.length === 0) return;
|
|
680
|
+
const { minMidi, maxMidi } = this._getPitchRange();
|
|
681
|
+
const noteRange = maxMidi - minMidi + 1;
|
|
682
|
+
const noteHeight = Math.max(2, this.waveHeight / noteRange);
|
|
683
|
+
const pixelsPerSecond = this.sampleRate / this.samplesPerPixel;
|
|
684
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
685
|
+
const color = this._getNoteColor();
|
|
686
|
+
for (const canvas of canvases) {
|
|
687
|
+
const chunkIdx = Number(canvas.dataset.index);
|
|
688
|
+
const chunkPixelStart = chunkIdx * MAX_CANVAS_WIDTH2;
|
|
689
|
+
const canvasWidth = canvas.width / dpr;
|
|
690
|
+
const ctx = canvas.getContext("2d");
|
|
691
|
+
if (!ctx) continue;
|
|
692
|
+
ctx.resetTransform();
|
|
693
|
+
ctx.clearRect(
|
|
694
|
+
0,
|
|
695
|
+
0,
|
|
696
|
+
canvas.width,
|
|
697
|
+
canvas.height
|
|
698
|
+
);
|
|
699
|
+
ctx.imageSmoothingEnabled = false;
|
|
700
|
+
ctx.scale(dpr, dpr);
|
|
701
|
+
const chunkStartTime = chunkPixelStart * this.samplesPerPixel / this.sampleRate;
|
|
702
|
+
const chunkEndTime = (chunkPixelStart + canvasWidth) * this.samplesPerPixel / this.sampleRate;
|
|
703
|
+
for (const note of this.midiNotes) {
|
|
704
|
+
const noteStart = note.time - this.clipOffsetSeconds;
|
|
705
|
+
const noteEnd = noteStart + note.duration;
|
|
706
|
+
if (noteEnd <= chunkStartTime || noteStart >= chunkEndTime) continue;
|
|
707
|
+
const x = noteStart * pixelsPerSecond - chunkPixelStart;
|
|
708
|
+
const w = Math.max(2, note.duration * pixelsPerSecond);
|
|
709
|
+
const y = (maxMidi - note.midi) / noteRange * this.waveHeight;
|
|
710
|
+
const alpha = 0.3 + note.velocity * 0.7;
|
|
711
|
+
ctx.fillStyle = color;
|
|
712
|
+
ctx.globalAlpha = alpha;
|
|
713
|
+
ctx.beginPath();
|
|
714
|
+
ctx.roundRect(x, y, w, noteHeight, 1);
|
|
715
|
+
ctx.fill();
|
|
716
|
+
}
|
|
717
|
+
ctx.globalAlpha = 1;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
connectedCallback() {
|
|
721
|
+
super.connectedCallback();
|
|
722
|
+
this._scheduleDraw();
|
|
723
|
+
}
|
|
724
|
+
disconnectedCallback() {
|
|
725
|
+
super.disconnectedCallback();
|
|
726
|
+
if (this._rafHandle !== null) {
|
|
727
|
+
cancelAnimationFrame(this._rafHandle);
|
|
728
|
+
this._rafHandle = null;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
render() {
|
|
732
|
+
if (this.length <= 0)
|
|
733
|
+
return html2`<div class="container" style="width: 0; height: ${this.waveHeight}px;"></div>`;
|
|
734
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
735
|
+
const visibleIndices = getVisibleChunkIndices(
|
|
736
|
+
this.length,
|
|
737
|
+
MAX_CANVAS_WIDTH2,
|
|
738
|
+
this.visibleStart,
|
|
739
|
+
this.visibleEnd,
|
|
740
|
+
this.originX
|
|
741
|
+
);
|
|
742
|
+
return html2`
|
|
743
|
+
<div class="container" style="width: ${this.length}px; height: ${this.waveHeight}px;">
|
|
744
|
+
${visibleIndices.map((i) => {
|
|
745
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH2;
|
|
746
|
+
const chunkWidth = Math.min(this.length - chunkLeft, MAX_CANVAS_WIDTH2);
|
|
747
|
+
return html2`<canvas
|
|
748
|
+
data-index=${i}
|
|
749
|
+
width=${chunkWidth * dpr}
|
|
750
|
+
height=${this.waveHeight * dpr}
|
|
751
|
+
style="left: ${chunkLeft}px; width: ${chunkWidth}px; height: ${this.waveHeight}px;"
|
|
752
|
+
></canvas>`;
|
|
753
|
+
})}
|
|
754
|
+
</div>
|
|
755
|
+
`;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
DawPianoRollElement.styles = css2`
|
|
759
|
+
:host {
|
|
760
|
+
display: block;
|
|
761
|
+
position: relative;
|
|
762
|
+
}
|
|
763
|
+
.container {
|
|
764
|
+
position: relative;
|
|
765
|
+
background: var(--daw-piano-roll-background, #1a1a2e);
|
|
766
|
+
}
|
|
767
|
+
canvas {
|
|
768
|
+
position: absolute;
|
|
769
|
+
top: 0;
|
|
770
|
+
image-rendering: pixelated;
|
|
771
|
+
image-rendering: crisp-edges;
|
|
772
|
+
}
|
|
773
|
+
`;
|
|
774
|
+
__decorateClass([
|
|
775
|
+
property4({ attribute: false })
|
|
776
|
+
], DawPianoRollElement.prototype, "midiNotes", 2);
|
|
777
|
+
__decorateClass([
|
|
778
|
+
property4({ type: Number, attribute: false })
|
|
779
|
+
], DawPianoRollElement.prototype, "length", 2);
|
|
780
|
+
__decorateClass([
|
|
781
|
+
property4({ type: Number, attribute: false })
|
|
782
|
+
], DawPianoRollElement.prototype, "waveHeight", 2);
|
|
783
|
+
__decorateClass([
|
|
784
|
+
property4({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
785
|
+
], DawPianoRollElement.prototype, "samplesPerPixel", 1);
|
|
786
|
+
__decorateClass([
|
|
787
|
+
property4({ type: Number, attribute: "sample-rate", noAccessor: true })
|
|
788
|
+
], DawPianoRollElement.prototype, "sampleRate", 1);
|
|
789
|
+
__decorateClass([
|
|
790
|
+
property4({ type: Number, attribute: false })
|
|
791
|
+
], DawPianoRollElement.prototype, "clipOffsetSeconds", 2);
|
|
792
|
+
__decorateClass([
|
|
793
|
+
property4({ type: Number, attribute: false })
|
|
794
|
+
], DawPianoRollElement.prototype, "visibleStart", 2);
|
|
795
|
+
__decorateClass([
|
|
796
|
+
property4({ type: Number, attribute: false })
|
|
797
|
+
], DawPianoRollElement.prototype, "visibleEnd", 2);
|
|
798
|
+
__decorateClass([
|
|
799
|
+
property4({ type: Number, attribute: false })
|
|
800
|
+
], DawPianoRollElement.prototype, "originX", 2);
|
|
801
|
+
__decorateClass([
|
|
802
|
+
property4({ type: Boolean, reflect: true })
|
|
803
|
+
], DawPianoRollElement.prototype, "selected", 2);
|
|
804
|
+
DawPianoRollElement = __decorateClass([
|
|
805
|
+
customElement4("daw-piano-roll")
|
|
806
|
+
], DawPianoRollElement);
|
|
807
|
+
|
|
808
|
+
// src/elements/daw-playhead.ts
|
|
809
|
+
import { LitElement as LitElement5, html as html3, css as css3 } from "lit";
|
|
810
|
+
import { customElement as customElement5 } from "lit/decorators.js";
|
|
538
811
|
|
|
539
812
|
// src/controllers/animation-controller.ts
|
|
540
813
|
var AnimationController = class {
|
|
@@ -567,14 +840,14 @@ var AnimationController = class {
|
|
|
567
840
|
};
|
|
568
841
|
|
|
569
842
|
// src/elements/daw-playhead.ts
|
|
570
|
-
var DawPlayheadElement = class extends
|
|
843
|
+
var DawPlayheadElement = class extends LitElement5 {
|
|
571
844
|
constructor() {
|
|
572
845
|
super(...arguments);
|
|
573
846
|
this._animation = new AnimationController(this);
|
|
574
847
|
this._line = null;
|
|
575
848
|
}
|
|
576
849
|
render() {
|
|
577
|
-
return
|
|
850
|
+
return html3`<div></div>`;
|
|
578
851
|
}
|
|
579
852
|
firstUpdated() {
|
|
580
853
|
this._line = this.shadowRoot.querySelector("div");
|
|
@@ -630,7 +903,7 @@ var DawPlayheadElement = class extends LitElement4 {
|
|
|
630
903
|
}
|
|
631
904
|
}
|
|
632
905
|
};
|
|
633
|
-
DawPlayheadElement.styles =
|
|
906
|
+
DawPlayheadElement.styles = css3`
|
|
634
907
|
:host {
|
|
635
908
|
position: absolute;
|
|
636
909
|
top: 0;
|
|
@@ -649,13 +922,13 @@ DawPlayheadElement.styles = css2`
|
|
|
649
922
|
}
|
|
650
923
|
`;
|
|
651
924
|
DawPlayheadElement = __decorateClass([
|
|
652
|
-
|
|
925
|
+
customElement5("daw-playhead")
|
|
653
926
|
], DawPlayheadElement);
|
|
654
927
|
|
|
655
928
|
// src/elements/daw-transport.ts
|
|
656
|
-
import { LitElement as
|
|
657
|
-
import { customElement as
|
|
658
|
-
var DawTransportElement = class extends
|
|
929
|
+
import { LitElement as LitElement6 } from "lit";
|
|
930
|
+
import { customElement as customElement6, property as property5 } from "lit/decorators.js";
|
|
931
|
+
var DawTransportElement = class extends LitElement6 {
|
|
659
932
|
constructor() {
|
|
660
933
|
super(...arguments);
|
|
661
934
|
this.for = "";
|
|
@@ -670,25 +943,25 @@ var DawTransportElement = class extends LitElement5 {
|
|
|
670
943
|
}
|
|
671
944
|
};
|
|
672
945
|
__decorateClass([
|
|
673
|
-
|
|
946
|
+
property5()
|
|
674
947
|
], DawTransportElement.prototype, "for", 2);
|
|
675
948
|
DawTransportElement = __decorateClass([
|
|
676
|
-
|
|
949
|
+
customElement6("daw-transport")
|
|
677
950
|
], DawTransportElement);
|
|
678
951
|
|
|
679
952
|
// src/elements/daw-play-button.ts
|
|
680
|
-
import { html as
|
|
681
|
-
import { customElement as
|
|
953
|
+
import { html as html4 } from "lit";
|
|
954
|
+
import { customElement as customElement7, state } from "lit/decorators.js";
|
|
682
955
|
|
|
683
956
|
// src/elements/daw-transport-button.ts
|
|
684
|
-
import { LitElement as
|
|
685
|
-
var DawTransportButton = class extends
|
|
957
|
+
import { LitElement as LitElement7, css as css4 } from "lit";
|
|
958
|
+
var DawTransportButton = class extends LitElement7 {
|
|
686
959
|
get target() {
|
|
687
960
|
const transport = this.closest("daw-transport");
|
|
688
961
|
return transport?.target ?? null;
|
|
689
962
|
}
|
|
690
963
|
};
|
|
691
|
-
DawTransportButton.styles =
|
|
964
|
+
DawTransportButton.styles = css4`
|
|
692
965
|
button {
|
|
693
966
|
cursor: pointer;
|
|
694
967
|
background: var(--daw-controls-background, #1a1a2e);
|
|
@@ -740,7 +1013,7 @@ var DawPlayButtonElement = class extends DawTransportButton {
|
|
|
740
1013
|
}
|
|
741
1014
|
}
|
|
742
1015
|
render() {
|
|
743
|
-
return
|
|
1016
|
+
return html4`
|
|
744
1017
|
<button part="button" ?disabled=${this._isRecording} @click=${this._onClick}>
|
|
745
1018
|
<slot>Play</slot>
|
|
746
1019
|
</button>
|
|
@@ -761,12 +1034,12 @@ __decorateClass([
|
|
|
761
1034
|
state()
|
|
762
1035
|
], DawPlayButtonElement.prototype, "_isRecording", 2);
|
|
763
1036
|
DawPlayButtonElement = __decorateClass([
|
|
764
|
-
|
|
1037
|
+
customElement7("daw-play-button")
|
|
765
1038
|
], DawPlayButtonElement);
|
|
766
1039
|
|
|
767
1040
|
// src/elements/daw-pause-button.ts
|
|
768
|
-
import { html as
|
|
769
|
-
import { customElement as
|
|
1041
|
+
import { html as html5, css as css5 } from "lit";
|
|
1042
|
+
import { customElement as customElement8, state as state2 } from "lit/decorators.js";
|
|
770
1043
|
var DawPauseButtonElement = class extends DawTransportButton {
|
|
771
1044
|
constructor() {
|
|
772
1045
|
super(...arguments);
|
|
@@ -780,6 +1053,12 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
780
1053
|
this._isRecording = false;
|
|
781
1054
|
this._isPaused = false;
|
|
782
1055
|
};
|
|
1056
|
+
this._onRecPause = () => {
|
|
1057
|
+
this._isPaused = true;
|
|
1058
|
+
};
|
|
1059
|
+
this._onRecResume = () => {
|
|
1060
|
+
this._isPaused = false;
|
|
1061
|
+
};
|
|
783
1062
|
}
|
|
784
1063
|
connectedCallback() {
|
|
785
1064
|
super.connectedCallback();
|
|
@@ -790,6 +1069,8 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
790
1069
|
target.addEventListener("daw-recording-start", this._onRecStart);
|
|
791
1070
|
target.addEventListener("daw-recording-complete", this._onRecEnd);
|
|
792
1071
|
target.addEventListener("daw-recording-error", this._onRecEnd);
|
|
1072
|
+
target.addEventListener("daw-recording-pause", this._onRecPause);
|
|
1073
|
+
target.addEventListener("daw-recording-resume", this._onRecResume);
|
|
793
1074
|
});
|
|
794
1075
|
}
|
|
795
1076
|
disconnectedCallback() {
|
|
@@ -798,11 +1079,13 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
798
1079
|
this._targetRef.removeEventListener("daw-recording-start", this._onRecStart);
|
|
799
1080
|
this._targetRef.removeEventListener("daw-recording-complete", this._onRecEnd);
|
|
800
1081
|
this._targetRef.removeEventListener("daw-recording-error", this._onRecEnd);
|
|
1082
|
+
this._targetRef.removeEventListener("daw-recording-pause", this._onRecPause);
|
|
1083
|
+
this._targetRef.removeEventListener("daw-recording-resume", this._onRecResume);
|
|
801
1084
|
this._targetRef = null;
|
|
802
1085
|
}
|
|
803
1086
|
}
|
|
804
1087
|
render() {
|
|
805
|
-
return
|
|
1088
|
+
return html5`
|
|
806
1089
|
<button part="button" ?data-paused=${this._isPaused} @click=${this._onClick}>
|
|
807
1090
|
<slot>Pause</slot>
|
|
808
1091
|
</button>
|
|
@@ -817,15 +1100,7 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
817
1100
|
return;
|
|
818
1101
|
}
|
|
819
1102
|
if (this._isRecording) {
|
|
820
|
-
|
|
821
|
-
target.resumeRecording();
|
|
822
|
-
target.play(target.currentTime);
|
|
823
|
-
this._isPaused = false;
|
|
824
|
-
} else {
|
|
825
|
-
target.pauseRecording();
|
|
826
|
-
target.pause();
|
|
827
|
-
this._isPaused = true;
|
|
828
|
-
}
|
|
1103
|
+
target.togglePauseRecording();
|
|
829
1104
|
} else {
|
|
830
1105
|
target.pause();
|
|
831
1106
|
}
|
|
@@ -833,7 +1108,7 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
833
1108
|
};
|
|
834
1109
|
DawPauseButtonElement.styles = [
|
|
835
1110
|
DawTransportButton.styles,
|
|
836
|
-
|
|
1111
|
+
css5`
|
|
837
1112
|
button[data-paused] {
|
|
838
1113
|
background: rgba(255, 255, 255, 0.1);
|
|
839
1114
|
border-color: var(--daw-controls-text, #e0d4c8);
|
|
@@ -847,15 +1122,15 @@ __decorateClass([
|
|
|
847
1122
|
state2()
|
|
848
1123
|
], DawPauseButtonElement.prototype, "_isRecording", 2);
|
|
849
1124
|
DawPauseButtonElement = __decorateClass([
|
|
850
|
-
|
|
1125
|
+
customElement8("daw-pause-button")
|
|
851
1126
|
], DawPauseButtonElement);
|
|
852
1127
|
|
|
853
1128
|
// src/elements/daw-stop-button.ts
|
|
854
|
-
import { html as
|
|
855
|
-
import { customElement as
|
|
1129
|
+
import { html as html6 } from "lit";
|
|
1130
|
+
import { customElement as customElement9 } from "lit/decorators.js";
|
|
856
1131
|
var DawStopButtonElement = class extends DawTransportButton {
|
|
857
1132
|
render() {
|
|
858
|
-
return
|
|
1133
|
+
return html6`
|
|
859
1134
|
<button part="button" @click=${this._onClick}>
|
|
860
1135
|
<slot>Stop</slot>
|
|
861
1136
|
</button>
|
|
@@ -870,18 +1145,31 @@ var DawStopButtonElement = class extends DawTransportButton {
|
|
|
870
1145
|
return;
|
|
871
1146
|
}
|
|
872
1147
|
if (target.isRecording) {
|
|
873
|
-
target.stopRecording()
|
|
1148
|
+
target.stopRecording().catch((err) => {
|
|
1149
|
+
console.warn("[dawcore] stopRecording failed: " + String(err));
|
|
1150
|
+
}).then(() => {
|
|
1151
|
+
try {
|
|
1152
|
+
target.stop();
|
|
1153
|
+
} catch (err) {
|
|
1154
|
+
console.warn("[dawcore] stop after stopRecording failed: " + String(err));
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
} else {
|
|
1158
|
+
try {
|
|
1159
|
+
target.stop();
|
|
1160
|
+
} catch (err) {
|
|
1161
|
+
console.warn("[dawcore] stop failed: " + String(err));
|
|
1162
|
+
}
|
|
874
1163
|
}
|
|
875
|
-
target.stop();
|
|
876
1164
|
}
|
|
877
1165
|
};
|
|
878
1166
|
DawStopButtonElement = __decorateClass([
|
|
879
|
-
|
|
1167
|
+
customElement9("daw-stop-button")
|
|
880
1168
|
], DawStopButtonElement);
|
|
881
1169
|
|
|
882
1170
|
// src/elements/daw-editor.ts
|
|
883
|
-
import { LitElement as
|
|
884
|
-
import { customElement as
|
|
1171
|
+
import { LitElement as LitElement10, html as html9, css as css9 } from "lit";
|
|
1172
|
+
import { customElement as customElement12, property as property8, state as state3 } from "lit/decorators.js";
|
|
885
1173
|
|
|
886
1174
|
// src/types.ts
|
|
887
1175
|
function isDomClip(desc) {
|
|
@@ -1366,9 +1654,9 @@ var PeakPipeline = class {
|
|
|
1366
1654
|
};
|
|
1367
1655
|
|
|
1368
1656
|
// src/elements/daw-track-controls.ts
|
|
1369
|
-
import { LitElement as
|
|
1370
|
-
import { customElement as
|
|
1371
|
-
var DawTrackControlsElement = class extends
|
|
1657
|
+
import { LitElement as LitElement8, html as html7, css as css6 } from "lit";
|
|
1658
|
+
import { customElement as customElement10, property as property6 } from "lit/decorators.js";
|
|
1659
|
+
var DawTrackControlsElement = class extends LitElement8 {
|
|
1372
1660
|
constructor() {
|
|
1373
1661
|
super(...arguments);
|
|
1374
1662
|
this.trackId = null;
|
|
@@ -1416,7 +1704,7 @@ var DawTrackControlsElement = class extends LitElement7 {
|
|
|
1416
1704
|
const volPercent = Math.round(this.volume * 100);
|
|
1417
1705
|
const panPercent = Math.round(Math.abs(this.pan) * 100);
|
|
1418
1706
|
const panDisplay = this.pan === 0 ? "C" : (this.pan > 0 ? "R" : "L") + panPercent;
|
|
1419
|
-
return
|
|
1707
|
+
return html7`
|
|
1420
1708
|
<div class="header">
|
|
1421
1709
|
<span class="name" title=${this.trackName}>${this.trackName || "Untitled"}</span>
|
|
1422
1710
|
<button class="remove-btn" @click=${this._onRemoveClick} title="Remove track">
|
|
@@ -1466,7 +1754,7 @@ var DawTrackControlsElement = class extends LitElement7 {
|
|
|
1466
1754
|
`;
|
|
1467
1755
|
}
|
|
1468
1756
|
};
|
|
1469
|
-
DawTrackControlsElement.styles =
|
|
1757
|
+
DawTrackControlsElement.styles = css6`
|
|
1470
1758
|
:host {
|
|
1471
1759
|
display: flex;
|
|
1472
1760
|
flex-direction: column;
|
|
@@ -1600,30 +1888,30 @@ DawTrackControlsElement.styles = css5`
|
|
|
1600
1888
|
}
|
|
1601
1889
|
`;
|
|
1602
1890
|
__decorateClass([
|
|
1603
|
-
|
|
1891
|
+
property6({ attribute: false })
|
|
1604
1892
|
], DawTrackControlsElement.prototype, "trackId", 2);
|
|
1605
1893
|
__decorateClass([
|
|
1606
|
-
|
|
1894
|
+
property6({ attribute: false })
|
|
1607
1895
|
], DawTrackControlsElement.prototype, "trackName", 2);
|
|
1608
1896
|
__decorateClass([
|
|
1609
|
-
|
|
1897
|
+
property6({ type: Number, attribute: false })
|
|
1610
1898
|
], DawTrackControlsElement.prototype, "volume", 2);
|
|
1611
1899
|
__decorateClass([
|
|
1612
|
-
|
|
1900
|
+
property6({ type: Number, attribute: false })
|
|
1613
1901
|
], DawTrackControlsElement.prototype, "pan", 2);
|
|
1614
1902
|
__decorateClass([
|
|
1615
|
-
|
|
1903
|
+
property6({ type: Boolean, attribute: false })
|
|
1616
1904
|
], DawTrackControlsElement.prototype, "muted", 2);
|
|
1617
1905
|
__decorateClass([
|
|
1618
|
-
|
|
1906
|
+
property6({ type: Boolean, attribute: false })
|
|
1619
1907
|
], DawTrackControlsElement.prototype, "soloed", 2);
|
|
1620
1908
|
DawTrackControlsElement = __decorateClass([
|
|
1621
|
-
|
|
1909
|
+
customElement10("daw-track-controls")
|
|
1622
1910
|
], DawTrackControlsElement);
|
|
1623
1911
|
|
|
1624
1912
|
// src/elements/daw-grid.ts
|
|
1625
|
-
import { LitElement as
|
|
1626
|
-
import { customElement as
|
|
1913
|
+
import { LitElement as LitElement9, html as html8, css as css7 } from "lit";
|
|
1914
|
+
import { customElement as customElement11, property as property7 } from "lit/decorators.js";
|
|
1627
1915
|
import { MIN_PIXELS_PER_UNIT } from "@waveform-playlist/core";
|
|
1628
1916
|
|
|
1629
1917
|
// src/utils/musical-tick-cache.ts
|
|
@@ -1654,8 +1942,8 @@ function getCachedMusicalTicks(params) {
|
|
|
1654
1942
|
}
|
|
1655
1943
|
|
|
1656
1944
|
// src/elements/daw-grid.ts
|
|
1657
|
-
var
|
|
1658
|
-
var DawGridElement = class extends
|
|
1945
|
+
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
1946
|
+
var DawGridElement = class extends LitElement9 {
|
|
1659
1947
|
constructor() {
|
|
1660
1948
|
super(...arguments);
|
|
1661
1949
|
this.ticksPerPixel = 24;
|
|
@@ -1683,25 +1971,25 @@ var DawGridElement = class extends LitElement8 {
|
|
|
1683
1971
|
}
|
|
1684
1972
|
}
|
|
1685
1973
|
render() {
|
|
1686
|
-
if (!this._tickData) return
|
|
1974
|
+
if (!this._tickData) return html8``;
|
|
1687
1975
|
const totalWidth = this.length;
|
|
1688
1976
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1689
1977
|
const indices = getVisibleChunkIndices(
|
|
1690
1978
|
totalWidth,
|
|
1691
|
-
|
|
1979
|
+
MAX_CANVAS_WIDTH3,
|
|
1692
1980
|
this.visibleStart,
|
|
1693
1981
|
this.visibleEnd
|
|
1694
1982
|
);
|
|
1695
|
-
return
|
|
1983
|
+
return html8`
|
|
1696
1984
|
<div class="container" style="width: ${totalWidth}px; height: ${this.height}px;">
|
|
1697
1985
|
${indices.map((i) => {
|
|
1698
|
-
const width = Math.min(
|
|
1699
|
-
return
|
|
1986
|
+
const width = Math.min(MAX_CANVAS_WIDTH3, totalWidth - i * MAX_CANVAS_WIDTH3);
|
|
1987
|
+
return html8`
|
|
1700
1988
|
<canvas
|
|
1701
1989
|
data-index=${i}
|
|
1702
1990
|
width=${width * dpr}
|
|
1703
1991
|
height=${this.height * dpr}
|
|
1704
|
-
style="left: ${i *
|
|
1992
|
+
style="left: ${i * MAX_CANVAS_WIDTH3}px; width: ${width}px; height: ${this.height}px;"
|
|
1705
1993
|
></canvas>
|
|
1706
1994
|
`;
|
|
1707
1995
|
})}
|
|
@@ -1725,8 +2013,8 @@ var DawGridElement = class extends LitElement8 {
|
|
|
1725
2013
|
const idx = Number(canvas.dataset.index);
|
|
1726
2014
|
const ctx = canvas.getContext("2d");
|
|
1727
2015
|
if (!ctx) continue;
|
|
1728
|
-
const chunkLeft = idx *
|
|
1729
|
-
const canvasWidth = Math.min(
|
|
2016
|
+
const chunkLeft = idx * MAX_CANVAS_WIDTH3;
|
|
2017
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH3, this.length - chunkLeft);
|
|
1730
2018
|
ctx.resetTransform();
|
|
1731
2019
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1732
2020
|
ctx.scale(dpr, dpr);
|
|
@@ -1757,7 +2045,7 @@ var DawGridElement = class extends LitElement8 {
|
|
|
1757
2045
|
}
|
|
1758
2046
|
}
|
|
1759
2047
|
};
|
|
1760
|
-
DawGridElement.styles =
|
|
2048
|
+
DawGridElement.styles = css7`
|
|
1761
2049
|
:host {
|
|
1762
2050
|
display: block;
|
|
1763
2051
|
position: absolute;
|
|
@@ -1775,33 +2063,33 @@ DawGridElement.styles = css6`
|
|
|
1775
2063
|
}
|
|
1776
2064
|
`;
|
|
1777
2065
|
__decorateClass([
|
|
1778
|
-
|
|
2066
|
+
property7({ type: Number, attribute: false })
|
|
1779
2067
|
], DawGridElement.prototype, "ticksPerPixel", 2);
|
|
1780
2068
|
__decorateClass([
|
|
1781
|
-
|
|
2069
|
+
property7({ attribute: false })
|
|
1782
2070
|
], DawGridElement.prototype, "meterEntries", 2);
|
|
1783
2071
|
__decorateClass([
|
|
1784
|
-
|
|
2072
|
+
property7({ type: Number, attribute: false })
|
|
1785
2073
|
], DawGridElement.prototype, "ppqn", 2);
|
|
1786
2074
|
__decorateClass([
|
|
1787
|
-
|
|
2075
|
+
property7({ type: Number, attribute: false })
|
|
1788
2076
|
], DawGridElement.prototype, "visibleStart", 2);
|
|
1789
2077
|
__decorateClass([
|
|
1790
|
-
|
|
2078
|
+
property7({ type: Number, attribute: false })
|
|
1791
2079
|
], DawGridElement.prototype, "visibleEnd", 2);
|
|
1792
2080
|
__decorateClass([
|
|
1793
|
-
|
|
2081
|
+
property7({ type: Number, attribute: false })
|
|
1794
2082
|
], DawGridElement.prototype, "length", 2);
|
|
1795
2083
|
__decorateClass([
|
|
1796
|
-
|
|
2084
|
+
property7({ type: Number, attribute: false })
|
|
1797
2085
|
], DawGridElement.prototype, "height", 2);
|
|
1798
2086
|
DawGridElement = __decorateClass([
|
|
1799
|
-
|
|
2087
|
+
customElement11("daw-grid")
|
|
1800
2088
|
], DawGridElement);
|
|
1801
2089
|
|
|
1802
2090
|
// src/styles/theme.ts
|
|
1803
|
-
import { css as
|
|
1804
|
-
var hostStyles =
|
|
2091
|
+
import { css as css8 } from "lit";
|
|
2092
|
+
var hostStyles = css8`
|
|
1805
2093
|
:host {
|
|
1806
2094
|
--daw-wave-color: #c49a6c;
|
|
1807
2095
|
--daw-progress-color: #63c75f;
|
|
@@ -1817,7 +2105,7 @@ var hostStyles = css7`
|
|
|
1817
2105
|
--daw-clip-header-text: #e0d4c8;
|
|
1818
2106
|
}
|
|
1819
2107
|
`;
|
|
1820
|
-
var clipStyles =
|
|
2108
|
+
var clipStyles = css8`
|
|
1821
2109
|
.clip-container {
|
|
1822
2110
|
position: absolute;
|
|
1823
2111
|
overflow: hidden;
|
|
@@ -2062,6 +2350,9 @@ var RecordingController = class {
|
|
|
2062
2350
|
constructor(host) {
|
|
2063
2351
|
this._sessions = /* @__PURE__ */ new Map();
|
|
2064
2352
|
this._workletLoadedCtx = null;
|
|
2353
|
+
/** Tracks worklet pause state explicitly so external consumers (editor,
|
|
2354
|
+
* pause button, spacebar) can share one source of truth. */
|
|
2355
|
+
this._isPaused = false;
|
|
2065
2356
|
this._host = host;
|
|
2066
2357
|
host.addController(this);
|
|
2067
2358
|
}
|
|
@@ -2076,6 +2367,9 @@ var RecordingController = class {
|
|
|
2076
2367
|
get isRecording() {
|
|
2077
2368
|
return this._sessions.size > 0;
|
|
2078
2369
|
}
|
|
2370
|
+
get isPaused() {
|
|
2371
|
+
return this._isPaused && this._sessions.size > 0;
|
|
2372
|
+
}
|
|
2079
2373
|
getSession(trackId) {
|
|
2080
2374
|
return this._sessions.get(trackId);
|
|
2081
2375
|
}
|
|
@@ -2148,7 +2442,9 @@ var RecordingController = class {
|
|
|
2148
2442
|
latencySamples,
|
|
2149
2443
|
wasOverdub: options.overdub ?? false,
|
|
2150
2444
|
_onTrackEnded: onTrackEnded,
|
|
2151
|
-
_audioTrack: audioTrack
|
|
2445
|
+
_audioTrack: audioTrack,
|
|
2446
|
+
stopAckResolve: null,
|
|
2447
|
+
stopping: false
|
|
2152
2448
|
};
|
|
2153
2449
|
this._sessions.set(trackId, session);
|
|
2154
2450
|
workletNode.port.onmessage = (e) => {
|
|
@@ -2186,25 +2482,69 @@ var RecordingController = class {
|
|
|
2186
2482
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2187
2483
|
if (!id) return;
|
|
2188
2484
|
const session = this._sessions.get(id);
|
|
2189
|
-
if (!session) return;
|
|
2485
|
+
if (!session || session.stopping) return;
|
|
2190
2486
|
session.workletNode.port.postMessage({ command: "pause" });
|
|
2487
|
+
this._isPaused = true;
|
|
2488
|
+
this._host.dispatchEvent(
|
|
2489
|
+
new CustomEvent("daw-recording-pause", {
|
|
2490
|
+
bubbles: true,
|
|
2491
|
+
composed: true,
|
|
2492
|
+
detail: { trackId: id }
|
|
2493
|
+
})
|
|
2494
|
+
);
|
|
2191
2495
|
}
|
|
2192
2496
|
resumeRecording(trackId) {
|
|
2193
2497
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2194
2498
|
if (!id) return;
|
|
2195
2499
|
const session = this._sessions.get(id);
|
|
2196
|
-
if (!session) return;
|
|
2500
|
+
if (!session || session.stopping) return;
|
|
2197
2501
|
session.workletNode.port.postMessage({ command: "resume" });
|
|
2502
|
+
this._isPaused = false;
|
|
2503
|
+
this._host.dispatchEvent(
|
|
2504
|
+
new CustomEvent("daw-recording-resume", {
|
|
2505
|
+
bubbles: true,
|
|
2506
|
+
composed: true,
|
|
2507
|
+
detail: { trackId: id }
|
|
2508
|
+
})
|
|
2509
|
+
);
|
|
2198
2510
|
}
|
|
2199
|
-
stopRecording(trackId) {
|
|
2511
|
+
async stopRecording(trackId) {
|
|
2200
2512
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2201
2513
|
if (!id) return;
|
|
2202
2514
|
const session = this._sessions.get(id);
|
|
2203
2515
|
if (!session) return;
|
|
2516
|
+
const wasPaused = this._isPaused;
|
|
2517
|
+
this._isPaused = false;
|
|
2518
|
+
session.stopping = true;
|
|
2204
2519
|
if (session.wasOverdub && typeof this._host.stop === "function") {
|
|
2205
2520
|
this._host.stop();
|
|
2206
2521
|
}
|
|
2207
|
-
|
|
2522
|
+
if (wasPaused) {
|
|
2523
|
+
session.workletNode.port.postMessage({ command: "stop" });
|
|
2524
|
+
} else {
|
|
2525
|
+
const stopAck = new Promise((resolve) => {
|
|
2526
|
+
session.stopAckResolve = resolve;
|
|
2527
|
+
});
|
|
2528
|
+
let timeoutId;
|
|
2529
|
+
const timeout = new Promise((resolve) => {
|
|
2530
|
+
timeoutId = setTimeout(resolve, 1e3);
|
|
2531
|
+
});
|
|
2532
|
+
session.workletNode.port.postMessage({ command: "stop" });
|
|
2533
|
+
await Promise.race([stopAck, timeout]);
|
|
2534
|
+
clearTimeout(timeoutId);
|
|
2535
|
+
session.stopAckResolve = null;
|
|
2536
|
+
let lastSamples = -1;
|
|
2537
|
+
let stable = 0;
|
|
2538
|
+
for (let i = 0; i < 50; i++) {
|
|
2539
|
+
if (session.totalSamples === lastSamples) {
|
|
2540
|
+
if (++stable >= 3) break;
|
|
2541
|
+
} else {
|
|
2542
|
+
stable = 0;
|
|
2543
|
+
lastSamples = session.totalSamples;
|
|
2544
|
+
}
|
|
2545
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2208
2548
|
session.source.disconnect();
|
|
2209
2549
|
session.workletNode.disconnect();
|
|
2210
2550
|
this._removeTrackEndedListener(session);
|
|
@@ -2276,8 +2616,20 @@ var RecordingController = class {
|
|
|
2276
2616
|
_onWorkletMessage(trackId, data) {
|
|
2277
2617
|
const session = this._sessions.get(trackId);
|
|
2278
2618
|
if (!session) return;
|
|
2279
|
-
const { channels } = data;
|
|
2280
|
-
|
|
2619
|
+
const { channels, done } = data;
|
|
2620
|
+
try {
|
|
2621
|
+
const hasSamples = !!(channels && channels.length > 0 && channels[0] && channels[0].length > 0);
|
|
2622
|
+
if (!hasSamples) return;
|
|
2623
|
+
this._processWorkletSamples(trackId, session, channels);
|
|
2624
|
+
} finally {
|
|
2625
|
+
if (done && session.stopAckResolve) {
|
|
2626
|
+
const resolve = session.stopAckResolve;
|
|
2627
|
+
session.stopAckResolve = null;
|
|
2628
|
+
resolve();
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
_processWorkletSamples(trackId, session, channels) {
|
|
2281
2633
|
const samplesProcessedBefore = session.totalSamples;
|
|
2282
2634
|
for (let ch = 0; ch < session.channelCount; ch++) {
|
|
2283
2635
|
if (channels[ch]) {
|
|
@@ -2285,6 +2637,7 @@ var RecordingController = class {
|
|
|
2285
2637
|
}
|
|
2286
2638
|
}
|
|
2287
2639
|
session.totalSamples += channels[0].length;
|
|
2640
|
+
if (session.stopAckResolve !== null) return;
|
|
2288
2641
|
for (let ch = 0; ch < session.channelCount; ch++) {
|
|
2289
2642
|
if (!channels[ch]) continue;
|
|
2290
2643
|
const oldPeakCount = Math.floor(session.peaks[ch].length / 2);
|
|
@@ -2619,6 +2972,7 @@ var ClipPointerHandler = class {
|
|
|
2619
2972
|
const trackId = boundary.dataset.trackId;
|
|
2620
2973
|
const edge = boundary.dataset.boundaryEdge;
|
|
2621
2974
|
if (!clipId || !trackId || edge !== "left" && edge !== "right") return false;
|
|
2975
|
+
if (this._host.isMidiClip(trackId, clipId)) return true;
|
|
2622
2976
|
this._beginDrag(edge === "left" ? "trim-left" : "trim-right", clipId, trackId, e);
|
|
2623
2977
|
this._boundaryEl = boundary;
|
|
2624
2978
|
return true;
|
|
@@ -2912,6 +3266,7 @@ async function loadFiles(host, files) {
|
|
|
2912
3266
|
pan: 0,
|
|
2913
3267
|
muted: false,
|
|
2914
3268
|
soloed: false,
|
|
3269
|
+
renderMode: "waveform",
|
|
2915
3270
|
clips: [
|
|
2916
3271
|
{
|
|
2917
3272
|
kind: "drop",
|
|
@@ -2924,7 +3279,10 @@ async function loadFiles(host, files) {
|
|
|
2924
3279
|
name,
|
|
2925
3280
|
fadeIn: 0,
|
|
2926
3281
|
fadeOut: 0,
|
|
2927
|
-
fadeType: "linear"
|
|
3282
|
+
fadeType: "linear",
|
|
3283
|
+
midiNotes: null,
|
|
3284
|
+
midiChannel: null,
|
|
3285
|
+
midiProgram: null
|
|
2928
3286
|
}
|
|
2929
3287
|
]
|
|
2930
3288
|
});
|
|
@@ -3011,7 +3369,10 @@ function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamp
|
|
|
3011
3369
|
name: "Recording",
|
|
3012
3370
|
fadeIn: 0,
|
|
3013
3371
|
fadeOut: 0,
|
|
3014
|
-
fadeType: "linear"
|
|
3372
|
+
fadeType: "linear",
|
|
3373
|
+
midiNotes: null,
|
|
3374
|
+
midiChannel: null,
|
|
3375
|
+
midiProgram: null
|
|
3015
3376
|
};
|
|
3016
3377
|
host._tracks = new Map(host._tracks).set(trackId, {
|
|
3017
3378
|
...desc,
|
|
@@ -3070,7 +3431,10 @@ function canSplitAtTime(host, time) {
|
|
|
3070
3431
|
const track = state5.tracks.find((t) => t.id === state5.selectedTrackId);
|
|
3071
3432
|
if (!track) return false;
|
|
3072
3433
|
const atSample = Math.round(time * host.effectiveSampleRate);
|
|
3073
|
-
|
|
3434
|
+
const clip = findClipAtSample(track.clips, atSample);
|
|
3435
|
+
if (!clip) return false;
|
|
3436
|
+
if (clip.midiNotes != null) return false;
|
|
3437
|
+
return true;
|
|
3074
3438
|
}
|
|
3075
3439
|
function performSplit(host, time) {
|
|
3076
3440
|
const { engine } = host;
|
|
@@ -3225,7 +3589,7 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
3225
3589
|
|
|
3226
3590
|
// src/elements/daw-editor.ts
|
|
3227
3591
|
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();";
|
|
3228
|
-
var DawEditorElement = class extends
|
|
3592
|
+
var DawEditorElement = class extends LitElement10 {
|
|
3229
3593
|
constructor() {
|
|
3230
3594
|
super(...arguments);
|
|
3231
3595
|
this._samplesPerPixel = 1024;
|
|
@@ -3384,7 +3748,10 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3384
3748
|
name: clipEl.name,
|
|
3385
3749
|
fadeIn: clipEl.fadeIn,
|
|
3386
3750
|
fadeOut: clipEl.fadeOut,
|
|
3387
|
-
fadeType: clipEl.fadeType
|
|
3751
|
+
fadeType: clipEl.fadeType,
|
|
3752
|
+
midiNotes: clipEl.midiNotes,
|
|
3753
|
+
midiChannel: clipEl.midiChannel,
|
|
3754
|
+
midiProgram: clipEl.midiProgram
|
|
3388
3755
|
};
|
|
3389
3756
|
this._loadAndAppendClip(trackId, clipDesc);
|
|
3390
3757
|
};
|
|
@@ -3435,6 +3802,9 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3435
3802
|
};
|
|
3436
3803
|
// --- Recording ---
|
|
3437
3804
|
this.recordingStream = null;
|
|
3805
|
+
/** Set in togglePauseRecording when Transport is paused alongside the
|
|
3806
|
+
* worklet, so resume can restart it. Cleared on resume and on stop. */
|
|
3807
|
+
this._wasPlayingDuringRecording = false;
|
|
3438
3808
|
}
|
|
3439
3809
|
get samplesPerPixel() {
|
|
3440
3810
|
return this._samplesPerPixel;
|
|
@@ -3534,6 +3904,17 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3534
3904
|
);
|
|
3535
3905
|
return result.get(clipId) ?? null;
|
|
3536
3906
|
}
|
|
3907
|
+
/**
|
|
3908
|
+
* Returns true if the clip is a MIDI clip (has midiNotes).
|
|
3909
|
+
* Used by ClipPointerHandler to make trim handles inert for MIDI clips.
|
|
3910
|
+
* Returns false for unknown track/clip IDs (defensive).
|
|
3911
|
+
*/
|
|
3912
|
+
isMidiClip(trackId, clipId) {
|
|
3913
|
+
const track = this._engineTracks.get(trackId);
|
|
3914
|
+
if (!track) return false;
|
|
3915
|
+
const clip = track.clips.find((c) => c.id === clipId);
|
|
3916
|
+
return clip?.midiNotes != null;
|
|
3917
|
+
}
|
|
3537
3918
|
get effectiveSampleRate() {
|
|
3538
3919
|
return this._resolvedSampleRate ?? this.sampleRate;
|
|
3539
3920
|
}
|
|
@@ -3883,6 +4264,65 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3883
4264
|
}
|
|
3884
4265
|
return clip;
|
|
3885
4266
|
}
|
|
4267
|
+
/**
|
|
4268
|
+
* Filter MIDI notes to only those with finite, in-range fields. Logs a
|
|
4269
|
+
* warning for each dropped note. Used by _buildMidiClip and the
|
|
4270
|
+
* _applyClipUpdate MIDI branch to prevent NaN propagation through the
|
|
4271
|
+
* timeline.
|
|
4272
|
+
*/
|
|
4273
|
+
_validMidiNotes(notes) {
|
|
4274
|
+
return notes.filter((n) => {
|
|
4275
|
+
const ok = Number.isFinite(n.time) && n.time >= 0 && Number.isFinite(n.duration) && n.duration > 0 && Number.isInteger(n.midi) && n.midi >= 0 && n.midi <= 127 && Number.isFinite(n.velocity) && n.velocity >= 0 && n.velocity <= 1;
|
|
4276
|
+
if (!ok) {
|
|
4277
|
+
console.warn("[dawcore] dropping malformed MIDI note: " + JSON.stringify(n));
|
|
4278
|
+
}
|
|
4279
|
+
return ok;
|
|
4280
|
+
});
|
|
4281
|
+
}
|
|
4282
|
+
/**
|
|
4283
|
+
* A clip descriptor is treated as MIDI when it has no audio src.
|
|
4284
|
+
* Includes placeholder MIDI clips (no notes, no duration yet — registered
|
|
4285
|
+
* with a 1s default span; notes upgrade via _applyClipUpdate). Warns when
|
|
4286
|
+
* a clip ambiguously has both src and midiNotes — the audio path runs
|
|
4287
|
+
* and notes would be silently ignored.
|
|
4288
|
+
*/
|
|
4289
|
+
_isMidiDescriptor(clipDesc) {
|
|
4290
|
+
if (clipDesc.src) {
|
|
4291
|
+
if (clipDesc.midiNotes != null) {
|
|
4292
|
+
console.warn(
|
|
4293
|
+
'[dawcore] clip "' + (clipDesc.name || (isDomClip(clipDesc) ? clipDesc.clipId : "?")) + '" has both src and midiNotes \u2014 treating as audio (notes will be ignored)'
|
|
4294
|
+
);
|
|
4295
|
+
}
|
|
4296
|
+
return false;
|
|
4297
|
+
}
|
|
4298
|
+
return true;
|
|
4299
|
+
}
|
|
4300
|
+
/**
|
|
4301
|
+
* Build an engine clip from a MIDI clip descriptor. Always returns a clip
|
|
4302
|
+
* — empty notes / no declared duration get a 1-second placeholder span so
|
|
4303
|
+
* the clip is reachable via `engine.updateTrack` once notes arrive.
|
|
4304
|
+
*/
|
|
4305
|
+
_buildMidiClip(clipDesc) {
|
|
4306
|
+
const sr = this.effectiveSampleRate;
|
|
4307
|
+
const notes = this._validMidiNotes(clipDesc.midiNotes ?? []);
|
|
4308
|
+
const noteSpanSeconds = notes.length ? notes.reduce((max, n) => Math.max(max, n.time + n.duration), 0) : 0;
|
|
4309
|
+
const sourceDurationSamples = Math.ceil(Math.max(noteSpanSeconds, clipDesc.duration, 1) * sr);
|
|
4310
|
+
const requestedDurationSamples = clipDesc.duration > 0 ? Math.round(clipDesc.duration * sr) : sourceDurationSamples;
|
|
4311
|
+
const clip = createClip3({
|
|
4312
|
+
startSample: Math.round(clipDesc.start * sr),
|
|
4313
|
+
durationSamples: requestedDurationSamples,
|
|
4314
|
+
offsetSamples: Math.round(clipDesc.offset * sr),
|
|
4315
|
+
sampleRate: sr,
|
|
4316
|
+
sourceDurationSamples,
|
|
4317
|
+
gain: clipDesc.gain,
|
|
4318
|
+
name: clipDesc.name,
|
|
4319
|
+
midiNotes: notes,
|
|
4320
|
+
midiChannel: clipDesc.midiChannel ?? void 0,
|
|
4321
|
+
midiProgram: clipDesc.midiProgram ?? void 0
|
|
4322
|
+
});
|
|
4323
|
+
if (isDomClip(clipDesc)) clip.id = clipDesc.clipId;
|
|
4324
|
+
return clip;
|
|
4325
|
+
}
|
|
3886
4326
|
/** Remove a single clip from all per-clip caches. Used by error rollbacks. */
|
|
3887
4327
|
_purgeClipCaches(clipId) {
|
|
3888
4328
|
const nextBuffers = new Map(this._clipBuffers);
|
|
@@ -3920,6 +4360,34 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3920
4360
|
}
|
|
3921
4361
|
const oldClip = t.clips[idx];
|
|
3922
4362
|
const sr = oldClip.sampleRate ?? this.effectiveSampleRate;
|
|
4363
|
+
const isMidiNow = clipEl.midiNotes != null;
|
|
4364
|
+
const wasMidi = oldClip.midiNotes != null;
|
|
4365
|
+
if (isMidiNow || wasMidi) {
|
|
4366
|
+
const notes = this._validMidiNotes(clipEl.midiNotes ?? []);
|
|
4367
|
+
const noteSpanSeconds = notes.length ? notes.reduce((max, n) => Math.max(max, n.time + n.duration), 0) : 0;
|
|
4368
|
+
const sourceDurationSamples = Math.ceil(Math.max(noteSpanSeconds, clipEl.duration, 1) * sr);
|
|
4369
|
+
const requestedDurationSamples = clipEl.duration > 0 ? Math.round(clipEl.duration * sr) : sourceDurationSamples;
|
|
4370
|
+
const updatedClip2 = {
|
|
4371
|
+
...oldClip,
|
|
4372
|
+
audioBuffer: void 0,
|
|
4373
|
+
startSample: Math.round(clipEl.start * sr),
|
|
4374
|
+
offsetSamples: Math.round(clipEl.offset * sr),
|
|
4375
|
+
durationSamples: requestedDurationSamples,
|
|
4376
|
+
sourceDurationSamples,
|
|
4377
|
+
gain: clipEl.gain,
|
|
4378
|
+
name: clipEl.name || oldClip.name,
|
|
4379
|
+
midiNotes: notes,
|
|
4380
|
+
midiChannel: clipEl.midiChannel ?? void 0,
|
|
4381
|
+
midiProgram: clipEl.midiProgram ?? void 0
|
|
4382
|
+
};
|
|
4383
|
+
const updatedClips2 = [...t.clips];
|
|
4384
|
+
updatedClips2[idx] = updatedClip2;
|
|
4385
|
+
const updatedTrack2 = { ...t, clips: updatedClips2 };
|
|
4386
|
+
this._engineTracks = new Map(this._engineTracks).set(trackId, updatedTrack2);
|
|
4387
|
+
this._purgeClipCaches(clipId);
|
|
4388
|
+
this._commitTrackChange(trackId, updatedTrack2);
|
|
4389
|
+
return;
|
|
4390
|
+
}
|
|
3923
4391
|
const newStartSample = Math.round(clipEl.start * sr);
|
|
3924
4392
|
const newDurationSamples = clipEl.duration > 0 ? Math.round(clipEl.duration * sr) : oldClip.durationSamples;
|
|
3925
4393
|
const newOffsetSamples = Math.round(clipEl.offset * sr);
|
|
@@ -3996,7 +4464,10 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
3996
4464
|
name: trackEl.name || "",
|
|
3997
4465
|
fadeIn: 0,
|
|
3998
4466
|
fadeOut: 0,
|
|
3999
|
-
fadeType: "linear"
|
|
4467
|
+
fadeType: "linear",
|
|
4468
|
+
midiNotes: null,
|
|
4469
|
+
midiChannel: null,
|
|
4470
|
+
midiProgram: null
|
|
4000
4471
|
});
|
|
4001
4472
|
} else {
|
|
4002
4473
|
for (const clipEl of clipEls) {
|
|
@@ -4012,7 +4483,10 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4012
4483
|
name: clipEl.name,
|
|
4013
4484
|
fadeIn: clipEl.fadeIn,
|
|
4014
4485
|
fadeOut: clipEl.fadeOut,
|
|
4015
|
-
fadeType: clipEl.fadeType
|
|
4486
|
+
fadeType: clipEl.fadeType,
|
|
4487
|
+
midiNotes: clipEl.midiNotes,
|
|
4488
|
+
midiChannel: clipEl.midiChannel,
|
|
4489
|
+
midiProgram: clipEl.midiProgram
|
|
4016
4490
|
});
|
|
4017
4491
|
}
|
|
4018
4492
|
}
|
|
@@ -4023,6 +4497,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4023
4497
|
pan: trackEl.pan,
|
|
4024
4498
|
muted: trackEl.muted,
|
|
4025
4499
|
soloed: trackEl.soloed,
|
|
4500
|
+
renderMode: trackEl.renderMode,
|
|
4026
4501
|
clips
|
|
4027
4502
|
};
|
|
4028
4503
|
}
|
|
@@ -4031,7 +4506,10 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4031
4506
|
try {
|
|
4032
4507
|
const clips = [];
|
|
4033
4508
|
for (const clipDesc of descriptor.clips) {
|
|
4034
|
-
if (
|
|
4509
|
+
if (this._isMidiDescriptor(clipDesc)) {
|
|
4510
|
+
clips.push(this._buildMidiClip(clipDesc));
|
|
4511
|
+
continue;
|
|
4512
|
+
}
|
|
4035
4513
|
try {
|
|
4036
4514
|
const waveformDataPromise = clipDesc.peaksSrc ? this._resolvePeaks(clipDesc.peaksSrc) : Promise.resolve(null);
|
|
4037
4515
|
const audioPromise = this._fetchAndDecode(clipDesc.src);
|
|
@@ -4243,7 +4721,11 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4243
4721
|
nextTracks.set(track.id, track);
|
|
4244
4722
|
}
|
|
4245
4723
|
this._engineTracks = nextTracks;
|
|
4246
|
-
|
|
4724
|
+
const audioTracks = engineState.tracks.filter((t) => {
|
|
4725
|
+
const desc = this._tracks.get(t.id);
|
|
4726
|
+
return desc?.renderMode !== "piano-roll";
|
|
4727
|
+
});
|
|
4728
|
+
syncPeaksForChangedClips(this, audioTracks);
|
|
4247
4729
|
}
|
|
4248
4730
|
});
|
|
4249
4731
|
engine.on("pause", () => {
|
|
@@ -4318,7 +4800,17 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4318
4800
|
if (config.pan !== void 0) trackEl.pan = config.pan;
|
|
4319
4801
|
if (config.muted) trackEl.setAttribute("muted", "");
|
|
4320
4802
|
if (config.soloed) trackEl.setAttribute("soloed", "");
|
|
4321
|
-
|
|
4803
|
+
const renderMode = config.renderMode ?? (config.midi ? "piano-roll" : void 0);
|
|
4804
|
+
if (renderMode !== void 0) trackEl.setAttribute("render-mode", renderMode);
|
|
4805
|
+
const clipConfigs = [...config.clips ?? []];
|
|
4806
|
+
if (config.midi) {
|
|
4807
|
+
clipConfigs.push({
|
|
4808
|
+
midiNotes: config.midi.notes,
|
|
4809
|
+
midiChannel: config.midi.channel,
|
|
4810
|
+
midiProgram: config.midi.program
|
|
4811
|
+
});
|
|
4812
|
+
}
|
|
4813
|
+
for (const clipConfig of clipConfigs) {
|
|
4322
4814
|
trackEl.appendChild(this._buildClipElement(clipConfig));
|
|
4323
4815
|
}
|
|
4324
4816
|
return this._awaitId(
|
|
@@ -4364,6 +4856,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4364
4856
|
if (partial.soloed) trackEl.setAttribute("soloed", "");
|
|
4365
4857
|
else trackEl.removeAttribute("soloed");
|
|
4366
4858
|
}
|
|
4859
|
+
if (partial.renderMode !== void 0) trackEl.setAttribute("render-mode", partial.renderMode);
|
|
4367
4860
|
return;
|
|
4368
4861
|
}
|
|
4369
4862
|
const oldDesc = this._tracks.get(trackId);
|
|
@@ -4374,7 +4867,8 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4374
4867
|
...partial.volume !== void 0 && { volume: partial.volume },
|
|
4375
4868
|
...partial.pan !== void 0 && { pan: partial.pan },
|
|
4376
4869
|
...partial.muted !== void 0 && { muted: partial.muted },
|
|
4377
|
-
...partial.soloed !== void 0 && { soloed: partial.soloed }
|
|
4870
|
+
...partial.soloed !== void 0 && { soloed: partial.soloed },
|
|
4871
|
+
...partial.renderMode !== void 0 && { renderMode: partial.renderMode }
|
|
4378
4872
|
};
|
|
4379
4873
|
this._tracks = new Map(this._tracks).set(trackId, newDesc);
|
|
4380
4874
|
if (this._engine) {
|
|
@@ -4509,6 +5003,11 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4509
5003
|
if (config.fadeIn !== void 0) clipEl.fadeIn = config.fadeIn;
|
|
4510
5004
|
if (config.fadeOut !== void 0) clipEl.fadeOut = config.fadeOut;
|
|
4511
5005
|
if (config.fadeType !== void 0) clipEl.setAttribute("fade-type", config.fadeType);
|
|
5006
|
+
if (config.midiNotes !== void 0) clipEl.midiNotes = config.midiNotes;
|
|
5007
|
+
if (config.midiChannel !== void 0)
|
|
5008
|
+
clipEl.setAttribute("midi-channel", String(config.midiChannel));
|
|
5009
|
+
if (config.midiProgram !== void 0)
|
|
5010
|
+
clipEl.setAttribute("midi-program", String(config.midiProgram));
|
|
4512
5011
|
return clipEl;
|
|
4513
5012
|
}
|
|
4514
5013
|
// --- Playback ---
|
|
@@ -4544,7 +5043,9 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4544
5043
|
}
|
|
4545
5044
|
/** Toggle between play and pause. */
|
|
4546
5045
|
togglePlayPause() {
|
|
4547
|
-
if (this.
|
|
5046
|
+
if (this.isRecording) {
|
|
5047
|
+
this.togglePauseRecording();
|
|
5048
|
+
} else if (this._isPlaying) {
|
|
4548
5049
|
this.pause();
|
|
4549
5050
|
} else {
|
|
4550
5051
|
this.play();
|
|
@@ -4618,14 +5119,41 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4618
5119
|
get isRecording() {
|
|
4619
5120
|
return this._recordingController.isRecording;
|
|
4620
5121
|
}
|
|
5122
|
+
get isRecordingPaused() {
|
|
5123
|
+
return this._recordingController.isPaused;
|
|
5124
|
+
}
|
|
4621
5125
|
pauseRecording() {
|
|
4622
5126
|
this._recordingController.pauseRecording();
|
|
4623
5127
|
}
|
|
4624
5128
|
resumeRecording() {
|
|
4625
5129
|
this._recordingController.resumeRecording();
|
|
5130
|
+
this._wasPlayingDuringRecording = false;
|
|
5131
|
+
}
|
|
5132
|
+
/**
|
|
5133
|
+
* Audacity-style pause toggle for active recordings: pauses both the
|
|
5134
|
+
* worklet capture and (if running) the playback Transport. On resume,
|
|
5135
|
+
* Transport restarts only if it was running before — non-overdub
|
|
5136
|
+
* recordings stay silent on resume.
|
|
5137
|
+
*/
|
|
5138
|
+
togglePauseRecording() {
|
|
5139
|
+
if (!this.isRecording) return;
|
|
5140
|
+
if (this.isRecordingPaused) {
|
|
5141
|
+
const wasPlaying = this._wasPlayingDuringRecording;
|
|
5142
|
+
this.resumeRecording();
|
|
5143
|
+
if (wasPlaying) {
|
|
5144
|
+
void this.play(this.currentTime);
|
|
5145
|
+
}
|
|
5146
|
+
} else {
|
|
5147
|
+
this.pauseRecording();
|
|
5148
|
+
if (this._isPlaying) {
|
|
5149
|
+
this._wasPlayingDuringRecording = true;
|
|
5150
|
+
this.pause();
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
4626
5153
|
}
|
|
4627
5154
|
stopRecording() {
|
|
4628
|
-
this.
|
|
5155
|
+
this._wasPlayingDuringRecording = false;
|
|
5156
|
+
return this._recordingController.stopRecording();
|
|
4629
5157
|
}
|
|
4630
5158
|
_addRecordedClip(trackId, buf, startSample, durSamples, offsetSamples = 0) {
|
|
4631
5159
|
addRecordedClip(this, trackId, buf, startSample, durSamples, offsetSamples);
|
|
@@ -4661,7 +5189,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4661
5189
|
const w = Math.floor(audibleSamples / renderSpp);
|
|
4662
5190
|
return rs.peaks.map((chPeaks, ch) => {
|
|
4663
5191
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
4664
|
-
return
|
|
5192
|
+
return html9`
|
|
4665
5193
|
<daw-waveform
|
|
4666
5194
|
data-recording-track=${trackId}
|
|
4667
5195
|
data-recording-channel=${ch}
|
|
@@ -4758,11 +5286,11 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4758
5286
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
4759
5287
|
};
|
|
4760
5288
|
});
|
|
4761
|
-
return
|
|
4762
|
-
${orderedTracks.length > 0 || this.indefinitePlayback ?
|
|
4763
|
-
${this.timescale ?
|
|
5289
|
+
return html9`
|
|
5290
|
+
${orderedTracks.length > 0 || this.indefinitePlayback ? html9`<div class="controls-column">
|
|
5291
|
+
${this.timescale ? html9`<div style="height: 30px;"></div>` : ""}
|
|
4764
5292
|
${orderedTracks.map(
|
|
4765
|
-
(t) =>
|
|
5293
|
+
(t) => html9`
|
|
4766
5294
|
<daw-track-controls
|
|
4767
5295
|
style="height: ${t.trackHeight}px;"
|
|
4768
5296
|
.trackId=${t.trackId}
|
|
@@ -4785,7 +5313,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4785
5313
|
@dragleave=${this._onDragLeave}
|
|
4786
5314
|
@drop=${this._onDrop}
|
|
4787
5315
|
>
|
|
4788
|
-
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ?
|
|
5316
|
+
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ? html9`<daw-ruler
|
|
4789
5317
|
.samplesPerPixel=${spp}
|
|
4790
5318
|
.sampleRate=${this.effectiveSampleRate}
|
|
4791
5319
|
.duration=${this._duration}
|
|
@@ -4795,7 +5323,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4795
5323
|
.ppqn=${this.ppqn}
|
|
4796
5324
|
.totalWidth=${this._totalWidth}
|
|
4797
5325
|
></daw-ruler>` : ""}
|
|
4798
|
-
${this.scaleMode === "beats" ?
|
|
5326
|
+
${this.scaleMode === "beats" ? html9`<daw-grid
|
|
4799
5327
|
style="top: ${this.timescale ? 30 : 0}px;"
|
|
4800
5328
|
.ticksPerPixel=${this.ticksPerPixel}
|
|
4801
5329
|
.meterEntries=${this._meterEntries}
|
|
@@ -4805,11 +5333,11 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4805
5333
|
.length=${this._totalWidth}
|
|
4806
5334
|
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight + 1, 0) : this._emptyGridHeight}
|
|
4807
5335
|
></daw-grid>` : ""}
|
|
4808
|
-
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ?
|
|
5336
|
+
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ? html9`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
4809
5337
|
<daw-playhead></daw-playhead>` : ""}
|
|
4810
5338
|
${orderedTracks.map((t) => {
|
|
4811
5339
|
const channelHeight = this.waveHeight;
|
|
4812
|
-
return
|
|
5340
|
+
return html9`
|
|
4813
5341
|
<div
|
|
4814
5342
|
class="track-row ${t.trackId === this._selectedTrackId ? "selected" : ""}"
|
|
4815
5343
|
style="height: ${t.trackHeight}px;"
|
|
@@ -4872,12 +5400,12 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4872
5400
|
const channels = segmentChannels ?? peakData?.data ?? [new Int16Array(0)];
|
|
4873
5401
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
4874
5402
|
const chH = this.waveHeight;
|
|
4875
|
-
return
|
|
5403
|
+
return html9` <div
|
|
4876
5404
|
class="clip-container"
|
|
4877
5405
|
style="left:${clipLeft}px;top:0;width:${width}px;height:${t.trackHeight}px;"
|
|
4878
5406
|
data-clip-id=${clip.id}
|
|
4879
5407
|
>
|
|
4880
|
-
${hdrH > 0 ?
|
|
5408
|
+
${hdrH > 0 ? html9`<div
|
|
4881
5409
|
class="clip-header"
|
|
4882
5410
|
data-clip-id=${clip.id}
|
|
4883
5411
|
data-track-id=${t.trackId}
|
|
@@ -4885,21 +5413,33 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4885
5413
|
>
|
|
4886
5414
|
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
4887
5415
|
</div>` : ""}
|
|
4888
|
-
${
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
.peaks=${chPeaks}
|
|
5416
|
+
${t.descriptor?.renderMode === "piano-roll" ? html9`<daw-piano-roll
|
|
5417
|
+
style="position:absolute;left:0;top:${hdrH}px;"
|
|
5418
|
+
.midiNotes=${clip.midiNotes ?? []}
|
|
4892
5419
|
.length=${peakData?.length ?? width}
|
|
4893
|
-
.waveHeight=${chH}
|
|
4894
|
-
.
|
|
4895
|
-
.
|
|
5420
|
+
.waveHeight=${chH * channels.length}
|
|
5421
|
+
.samplesPerPixel=${this._renderSpp}
|
|
5422
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
5423
|
+
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
4896
5424
|
.visibleStart=${this._viewport.visibleStart}
|
|
4897
5425
|
.visibleEnd=${this._viewport.visibleEnd}
|
|
4898
5426
|
.originX=${clipLeft}
|
|
4899
|
-
|
|
4900
|
-
></daw-
|
|
5427
|
+
?selected=${t.trackId === this._selectedTrackId}
|
|
5428
|
+
></daw-piano-roll>` : channels.map(
|
|
5429
|
+
(chPeaks, chIdx) => html9` <daw-waveform
|
|
5430
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
5431
|
+
.peaks=${chPeaks}
|
|
5432
|
+
.length=${peakData?.length ?? width}
|
|
5433
|
+
.waveHeight=${chH}
|
|
5434
|
+
.barWidth=${this.barWidth}
|
|
5435
|
+
.barGap=${this.barGap}
|
|
5436
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
5437
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
5438
|
+
.originX=${clipLeft}
|
|
5439
|
+
.segments=${clipSegments}
|
|
5440
|
+
></daw-waveform>`
|
|
4901
5441
|
)}
|
|
4902
|
-
${this.interactiveClips ?
|
|
5442
|
+
${this.interactiveClips ? html9` <div
|
|
4903
5443
|
class="clip-boundary"
|
|
4904
5444
|
data-boundary-edge="left"
|
|
4905
5445
|
data-clip-id=${clip.id}
|
|
@@ -4925,7 +5465,7 @@ var DawEditorElement = class extends LitElement9 {
|
|
|
4925
5465
|
};
|
|
4926
5466
|
DawEditorElement.styles = [
|
|
4927
5467
|
hostStyles,
|
|
4928
|
-
|
|
5468
|
+
css9`
|
|
4929
5469
|
:host {
|
|
4930
5470
|
display: flex;
|
|
4931
5471
|
position: relative;
|
|
@@ -4973,64 +5513,64 @@ DawEditorElement.styles = [
|
|
|
4973
5513
|
];
|
|
4974
5514
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
4975
5515
|
__decorateClass([
|
|
4976
|
-
|
|
5516
|
+
property8({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
4977
5517
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
4978
5518
|
__decorateClass([
|
|
4979
|
-
|
|
5519
|
+
property8({ type: Number, attribute: "wave-height" })
|
|
4980
5520
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
4981
5521
|
__decorateClass([
|
|
4982
|
-
|
|
5522
|
+
property8({ type: Boolean })
|
|
4983
5523
|
], DawEditorElement.prototype, "timescale", 2);
|
|
4984
5524
|
__decorateClass([
|
|
4985
|
-
|
|
5525
|
+
property8({ type: Boolean })
|
|
4986
5526
|
], DawEditorElement.prototype, "mono", 2);
|
|
4987
5527
|
__decorateClass([
|
|
4988
|
-
|
|
5528
|
+
property8({ type: Number, attribute: "bar-width" })
|
|
4989
5529
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
4990
5530
|
__decorateClass([
|
|
4991
|
-
|
|
5531
|
+
property8({ type: Number, attribute: "bar-gap" })
|
|
4992
5532
|
], DawEditorElement.prototype, "barGap", 2);
|
|
4993
5533
|
__decorateClass([
|
|
4994
|
-
|
|
5534
|
+
property8({ type: Boolean, attribute: "file-drop" })
|
|
4995
5535
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
4996
5536
|
__decorateClass([
|
|
4997
|
-
|
|
5537
|
+
property8({ type: Boolean, attribute: "clip-headers" })
|
|
4998
5538
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
4999
5539
|
__decorateClass([
|
|
5000
|
-
|
|
5540
|
+
property8({ type: Number, attribute: "clip-header-height" })
|
|
5001
5541
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
5002
5542
|
__decorateClass([
|
|
5003
|
-
|
|
5543
|
+
property8({ type: Boolean, attribute: "interactive-clips" })
|
|
5004
5544
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
5005
5545
|
__decorateClass([
|
|
5006
|
-
|
|
5546
|
+
property8({ type: Boolean, attribute: "indefinite-playback" })
|
|
5007
5547
|
], DawEditorElement.prototype, "indefinitePlayback", 2);
|
|
5008
5548
|
__decorateClass([
|
|
5009
|
-
|
|
5549
|
+
property8({ type: String, attribute: "scale-mode" })
|
|
5010
5550
|
], DawEditorElement.prototype, "scaleMode", 2);
|
|
5011
5551
|
__decorateClass([
|
|
5012
|
-
|
|
5552
|
+
property8({ type: Number, attribute: "ticks-per-pixel", noAccessor: true })
|
|
5013
5553
|
], DawEditorElement.prototype, "ticksPerPixel", 1);
|
|
5014
5554
|
__decorateClass([
|
|
5015
|
-
|
|
5555
|
+
property8({ type: Number, noAccessor: true })
|
|
5016
5556
|
], DawEditorElement.prototype, "bpm", 1);
|
|
5017
5557
|
__decorateClass([
|
|
5018
|
-
|
|
5558
|
+
property8({ attribute: false })
|
|
5019
5559
|
], DawEditorElement.prototype, "timeSignature", 2);
|
|
5020
5560
|
__decorateClass([
|
|
5021
|
-
|
|
5561
|
+
property8({ attribute: false })
|
|
5022
5562
|
], DawEditorElement.prototype, "meterEntries", 2);
|
|
5023
5563
|
__decorateClass([
|
|
5024
|
-
|
|
5564
|
+
property8({ type: Number, noAccessor: true })
|
|
5025
5565
|
], DawEditorElement.prototype, "ppqn", 1);
|
|
5026
5566
|
__decorateClass([
|
|
5027
|
-
|
|
5567
|
+
property8({ type: String, attribute: "snap-to" })
|
|
5028
5568
|
], DawEditorElement.prototype, "snapTo", 2);
|
|
5029
5569
|
__decorateClass([
|
|
5030
|
-
|
|
5570
|
+
property8({ attribute: false })
|
|
5031
5571
|
], DawEditorElement.prototype, "secondsToTicks", 2);
|
|
5032
5572
|
__decorateClass([
|
|
5033
|
-
|
|
5573
|
+
property8({ attribute: false })
|
|
5034
5574
|
], DawEditorElement.prototype, "ticksToSeconds", 2);
|
|
5035
5575
|
__decorateClass([
|
|
5036
5576
|
state3()
|
|
@@ -5054,18 +5594,18 @@ __decorateClass([
|
|
|
5054
5594
|
state3()
|
|
5055
5595
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
5056
5596
|
__decorateClass([
|
|
5057
|
-
|
|
5597
|
+
property8({ attribute: false })
|
|
5058
5598
|
], DawEditorElement.prototype, "adapter", 1);
|
|
5059
5599
|
__decorateClass([
|
|
5060
|
-
|
|
5600
|
+
property8({ attribute: "eager-resume" })
|
|
5061
5601
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
5062
5602
|
DawEditorElement = __decorateClass([
|
|
5063
|
-
|
|
5603
|
+
customElement12("daw-editor")
|
|
5064
5604
|
], DawEditorElement);
|
|
5065
5605
|
|
|
5066
5606
|
// src/elements/daw-ruler.ts
|
|
5067
|
-
import { LitElement as
|
|
5068
|
-
import { customElement as
|
|
5607
|
+
import { LitElement as LitElement11, html as html10, css as css10 } from "lit";
|
|
5608
|
+
import { customElement as customElement13, property as property9 } from "lit/decorators.js";
|
|
5069
5609
|
|
|
5070
5610
|
// src/utils/time-format.ts
|
|
5071
5611
|
function formatTime(milliseconds) {
|
|
@@ -5116,8 +5656,8 @@ function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight
|
|
|
5116
5656
|
}
|
|
5117
5657
|
|
|
5118
5658
|
// src/elements/daw-ruler.ts
|
|
5119
|
-
var
|
|
5120
|
-
var DawRulerElement = class extends
|
|
5659
|
+
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
5660
|
+
var DawRulerElement = class extends LitElement11 {
|
|
5121
5661
|
constructor() {
|
|
5122
5662
|
super(...arguments);
|
|
5123
5663
|
this.samplesPerPixel = 1024;
|
|
@@ -5161,33 +5701,33 @@ var DawRulerElement = class extends LitElement10 {
|
|
|
5161
5701
|
}
|
|
5162
5702
|
render() {
|
|
5163
5703
|
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
5164
|
-
if (widthX <= 0) return
|
|
5165
|
-
const totalChunks = Math.ceil(widthX /
|
|
5704
|
+
if (widthX <= 0) return html10``;
|
|
5705
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH4);
|
|
5166
5706
|
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
5167
5707
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
5168
5708
|
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
5169
5709
|
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
5170
|
-
return
|
|
5710
|
+
return html10`
|
|
5171
5711
|
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
5172
5712
|
${indices.map((i) => {
|
|
5173
|
-
const width = Math.min(
|
|
5174
|
-
return
|
|
5713
|
+
const width = Math.min(MAX_CANVAS_WIDTH4, widthX - i * MAX_CANVAS_WIDTH4);
|
|
5714
|
+
return html10`
|
|
5175
5715
|
<canvas
|
|
5176
5716
|
data-index=${i}
|
|
5177
5717
|
width=${width * dpr}
|
|
5178
5718
|
height=${this.rulerHeight * dpr}
|
|
5179
|
-
style="left: ${i *
|
|
5719
|
+
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
5180
5720
|
></canvas>
|
|
5181
5721
|
`;
|
|
5182
5722
|
})}
|
|
5183
5723
|
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
5184
|
-
(t) =>
|
|
5724
|
+
(t) => html10`<span
|
|
5185
5725
|
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
5186
5726
|
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
5187
5727
|
>${t.label}</span
|
|
5188
5728
|
>`
|
|
5189
5729
|
) : temporalLabels.map(
|
|
5190
|
-
({ pix, text }) =>
|
|
5730
|
+
({ pix, text }) => html10`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
5191
5731
|
)}
|
|
5192
5732
|
</div>
|
|
5193
5733
|
`;
|
|
@@ -5205,8 +5745,8 @@ var DawRulerElement = class extends LitElement10 {
|
|
|
5205
5745
|
const idx = Number(canvas.dataset.index);
|
|
5206
5746
|
const ctx = canvas.getContext("2d");
|
|
5207
5747
|
if (!ctx) continue;
|
|
5208
|
-
const canvasWidth = Math.min(
|
|
5209
|
-
const globalOffset = idx *
|
|
5748
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, widthX - idx * MAX_CANVAS_WIDTH4);
|
|
5749
|
+
const globalOffset = idx * MAX_CANVAS_WIDTH4;
|
|
5210
5750
|
ctx.resetTransform();
|
|
5211
5751
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
5212
5752
|
ctx.scale(dpr, dpr);
|
|
@@ -5238,7 +5778,7 @@ var DawRulerElement = class extends LitElement10 {
|
|
|
5238
5778
|
}
|
|
5239
5779
|
}
|
|
5240
5780
|
};
|
|
5241
|
-
DawRulerElement.styles =
|
|
5781
|
+
DawRulerElement.styles = css10`
|
|
5242
5782
|
:host {
|
|
5243
5783
|
display: block;
|
|
5244
5784
|
position: relative;
|
|
@@ -5264,40 +5804,40 @@ DawRulerElement.styles = css9`
|
|
|
5264
5804
|
}
|
|
5265
5805
|
`;
|
|
5266
5806
|
__decorateClass([
|
|
5267
|
-
|
|
5807
|
+
property9({ type: Number, attribute: false })
|
|
5268
5808
|
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
5269
5809
|
__decorateClass([
|
|
5270
|
-
|
|
5810
|
+
property9({ type: Number, attribute: false })
|
|
5271
5811
|
], DawRulerElement.prototype, "sampleRate", 2);
|
|
5272
5812
|
__decorateClass([
|
|
5273
|
-
|
|
5813
|
+
property9({ type: Number, attribute: false })
|
|
5274
5814
|
], DawRulerElement.prototype, "duration", 2);
|
|
5275
5815
|
__decorateClass([
|
|
5276
|
-
|
|
5816
|
+
property9({ type: Number, attribute: false })
|
|
5277
5817
|
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
5278
5818
|
__decorateClass([
|
|
5279
|
-
|
|
5819
|
+
property9({ type: String, attribute: false })
|
|
5280
5820
|
], DawRulerElement.prototype, "scaleMode", 2);
|
|
5281
5821
|
__decorateClass([
|
|
5282
|
-
|
|
5822
|
+
property9({ type: Number, attribute: false })
|
|
5283
5823
|
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
5284
5824
|
__decorateClass([
|
|
5285
|
-
|
|
5825
|
+
property9({ attribute: false })
|
|
5286
5826
|
], DawRulerElement.prototype, "meterEntries", 2);
|
|
5287
5827
|
__decorateClass([
|
|
5288
|
-
|
|
5828
|
+
property9({ type: Number, attribute: false })
|
|
5289
5829
|
], DawRulerElement.prototype, "ppqn", 2);
|
|
5290
5830
|
__decorateClass([
|
|
5291
|
-
|
|
5831
|
+
property9({ type: Number, attribute: false })
|
|
5292
5832
|
], DawRulerElement.prototype, "totalWidth", 2);
|
|
5293
5833
|
DawRulerElement = __decorateClass([
|
|
5294
|
-
|
|
5834
|
+
customElement13("daw-ruler")
|
|
5295
5835
|
], DawRulerElement);
|
|
5296
5836
|
|
|
5297
5837
|
// src/elements/daw-selection.ts
|
|
5298
|
-
import { LitElement as
|
|
5299
|
-
import { customElement as
|
|
5300
|
-
var DawSelectionElement = class extends
|
|
5838
|
+
import { LitElement as LitElement12, html as html11, css as css11 } from "lit";
|
|
5839
|
+
import { customElement as customElement14, property as property10 } from "lit/decorators.js";
|
|
5840
|
+
var DawSelectionElement = class extends LitElement12 {
|
|
5301
5841
|
constructor() {
|
|
5302
5842
|
super(...arguments);
|
|
5303
5843
|
this.startPx = 0;
|
|
@@ -5306,11 +5846,11 @@ var DawSelectionElement = class extends LitElement11 {
|
|
|
5306
5846
|
render() {
|
|
5307
5847
|
const left = Math.min(this.startPx, this.endPx);
|
|
5308
5848
|
const width = Math.abs(this.endPx - this.startPx);
|
|
5309
|
-
if (width === 0) return
|
|
5310
|
-
return
|
|
5849
|
+
if (width === 0) return html11``;
|
|
5850
|
+
return html11`<div style="left: ${left}px; width: ${width}px;"></div>`;
|
|
5311
5851
|
}
|
|
5312
5852
|
};
|
|
5313
|
-
DawSelectionElement.styles =
|
|
5853
|
+
DawSelectionElement.styles = css11`
|
|
5314
5854
|
:host {
|
|
5315
5855
|
position: absolute;
|
|
5316
5856
|
top: 0;
|
|
@@ -5327,18 +5867,18 @@ DawSelectionElement.styles = css10`
|
|
|
5327
5867
|
}
|
|
5328
5868
|
`;
|
|
5329
5869
|
__decorateClass([
|
|
5330
|
-
|
|
5870
|
+
property10({ type: Number, attribute: false })
|
|
5331
5871
|
], DawSelectionElement.prototype, "startPx", 2);
|
|
5332
5872
|
__decorateClass([
|
|
5333
|
-
|
|
5873
|
+
property10({ type: Number, attribute: false })
|
|
5334
5874
|
], DawSelectionElement.prototype, "endPx", 2);
|
|
5335
5875
|
DawSelectionElement = __decorateClass([
|
|
5336
|
-
|
|
5876
|
+
customElement14("daw-selection")
|
|
5337
5877
|
], DawSelectionElement);
|
|
5338
5878
|
|
|
5339
5879
|
// src/elements/daw-record-button.ts
|
|
5340
|
-
import { html as
|
|
5341
|
-
import { customElement as
|
|
5880
|
+
import { html as html12, css as css12 } from "lit";
|
|
5881
|
+
import { customElement as customElement15, state as state4 } from "lit/decorators.js";
|
|
5342
5882
|
var DawRecordButtonElement = class extends DawTransportButton {
|
|
5343
5883
|
constructor() {
|
|
5344
5884
|
super(...arguments);
|
|
@@ -5379,7 +5919,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
5379
5919
|
}
|
|
5380
5920
|
}
|
|
5381
5921
|
render() {
|
|
5382
|
-
return
|
|
5922
|
+
return html12`
|
|
5383
5923
|
<button part="button" ?data-recording=${this._isRecording} @click=${this._onClick}>
|
|
5384
5924
|
<slot>Record</slot>
|
|
5385
5925
|
</button>
|
|
@@ -5399,7 +5939,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
5399
5939
|
};
|
|
5400
5940
|
DawRecordButtonElement.styles = [
|
|
5401
5941
|
DawTransportButton.styles,
|
|
5402
|
-
|
|
5942
|
+
css12`
|
|
5403
5943
|
button[data-recording] {
|
|
5404
5944
|
color: #d08070;
|
|
5405
5945
|
border-color: #d08070;
|
|
@@ -5411,14 +5951,14 @@ __decorateClass([
|
|
|
5411
5951
|
state4()
|
|
5412
5952
|
], DawRecordButtonElement.prototype, "_isRecording", 2);
|
|
5413
5953
|
DawRecordButtonElement = __decorateClass([
|
|
5414
|
-
|
|
5954
|
+
customElement15("daw-record-button")
|
|
5415
5955
|
], DawRecordButtonElement);
|
|
5416
5956
|
|
|
5417
5957
|
// src/elements/daw-keyboard-shortcuts.ts
|
|
5418
|
-
import { LitElement as
|
|
5419
|
-
import { customElement as
|
|
5958
|
+
import { LitElement as LitElement13 } from "lit";
|
|
5959
|
+
import { customElement as customElement16, property as property11 } from "lit/decorators.js";
|
|
5420
5960
|
import { handleKeyboardEvent } from "@waveform-playlist/core";
|
|
5421
|
-
var DawKeyboardShortcutsElement = class extends
|
|
5961
|
+
var DawKeyboardShortcutsElement = class extends LitElement13 {
|
|
5422
5962
|
constructor() {
|
|
5423
5963
|
super(...arguments);
|
|
5424
5964
|
this.playback = false;
|
|
@@ -5572,16 +6112,16 @@ var DawKeyboardShortcutsElement = class extends LitElement12 {
|
|
|
5572
6112
|
}
|
|
5573
6113
|
};
|
|
5574
6114
|
__decorateClass([
|
|
5575
|
-
|
|
6115
|
+
property11({ type: Boolean })
|
|
5576
6116
|
], DawKeyboardShortcutsElement.prototype, "playback", 2);
|
|
5577
6117
|
__decorateClass([
|
|
5578
|
-
|
|
6118
|
+
property11({ type: Boolean })
|
|
5579
6119
|
], DawKeyboardShortcutsElement.prototype, "splitting", 2);
|
|
5580
6120
|
__decorateClass([
|
|
5581
|
-
|
|
6121
|
+
property11({ type: Boolean })
|
|
5582
6122
|
], DawKeyboardShortcutsElement.prototype, "undo", 2);
|
|
5583
6123
|
DawKeyboardShortcutsElement = __decorateClass([
|
|
5584
|
-
|
|
6124
|
+
customElement16("daw-keyboard-shortcuts")
|
|
5585
6125
|
], DawKeyboardShortcutsElement);
|
|
5586
6126
|
export {
|
|
5587
6127
|
AudioResumeController,
|
|
@@ -5591,6 +6131,7 @@ export {
|
|
|
5591
6131
|
DawGridElement,
|
|
5592
6132
|
DawKeyboardShortcutsElement,
|
|
5593
6133
|
DawPauseButtonElement,
|
|
6134
|
+
DawPianoRollElement,
|
|
5594
6135
|
DawPlayButtonElement,
|
|
5595
6136
|
DawPlayheadElement,
|
|
5596
6137
|
DawRecordButtonElement,
|