@dawcore/components 0.0.14 → 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/README.md +55 -3
- 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.js
CHANGED
|
@@ -45,6 +45,7 @@ __export(index_exports, {
|
|
|
45
45
|
DawGridElement: () => DawGridElement,
|
|
46
46
|
DawKeyboardShortcutsElement: () => DawKeyboardShortcutsElement,
|
|
47
47
|
DawPauseButtonElement: () => DawPauseButtonElement,
|
|
48
|
+
DawPianoRollElement: () => DawPianoRollElement,
|
|
48
49
|
DawPlayButtonElement: () => DawPlayButtonElement,
|
|
49
50
|
DawPlayheadElement: () => DawPlayheadElement,
|
|
50
51
|
DawRecordButtonElement: () => DawRecordButtonElement,
|
|
@@ -79,11 +80,48 @@ var DawClipElement = class extends import_lit.LitElement {
|
|
|
79
80
|
this.fadeIn = 0;
|
|
80
81
|
this.fadeOut = 0;
|
|
81
82
|
this.fadeType = "linear";
|
|
83
|
+
this.midiNotes = null;
|
|
84
|
+
this._midiChannel = null;
|
|
85
|
+
this._midiProgram = null;
|
|
82
86
|
this.clipId = crypto.randomUUID();
|
|
83
87
|
// Removal is detected by the editor's MutationObserver — detached elements
|
|
84
88
|
// cannot bubble events to ancestors.
|
|
85
89
|
this._hasRendered = false;
|
|
86
90
|
}
|
|
91
|
+
get midiChannel() {
|
|
92
|
+
return this._midiChannel;
|
|
93
|
+
}
|
|
94
|
+
set midiChannel(value) {
|
|
95
|
+
const old = this._midiChannel;
|
|
96
|
+
if (value === null) {
|
|
97
|
+
this._midiChannel = null;
|
|
98
|
+
this.requestUpdate("midiChannel", old);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 15) {
|
|
102
|
+
console.warn("[dawcore] daw-clip midi-channel " + value + " is out of range 0-15 \u2014 ignored");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this._midiChannel = value;
|
|
106
|
+
this.requestUpdate("midiChannel", old);
|
|
107
|
+
}
|
|
108
|
+
get midiProgram() {
|
|
109
|
+
return this._midiProgram;
|
|
110
|
+
}
|
|
111
|
+
set midiProgram(value) {
|
|
112
|
+
const old = this._midiProgram;
|
|
113
|
+
if (value === null) {
|
|
114
|
+
this._midiProgram = null;
|
|
115
|
+
this.requestUpdate("midiProgram", old);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || value > 127) {
|
|
119
|
+
console.warn("[dawcore] daw-clip midi-program " + value + " is out of range 0-127 \u2014 ignored");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
this._midiProgram = value;
|
|
123
|
+
this.requestUpdate("midiProgram", old);
|
|
124
|
+
}
|
|
87
125
|
// Light DOM — no visual rendering, just a data container
|
|
88
126
|
createRenderRoot() {
|
|
89
127
|
return this;
|
|
@@ -115,7 +153,10 @@ var DawClipElement = class extends import_lit.LitElement {
|
|
|
115
153
|
"name",
|
|
116
154
|
"fadeIn",
|
|
117
155
|
"fadeOut",
|
|
118
|
-
"fadeType"
|
|
156
|
+
"fadeType",
|
|
157
|
+
"midiNotes",
|
|
158
|
+
"midiChannel",
|
|
159
|
+
"midiProgram"
|
|
119
160
|
];
|
|
120
161
|
if (clipProps.some((p) => changed.has(p))) {
|
|
121
162
|
const trackEl = this.closest("daw-track");
|
|
@@ -162,6 +203,15 @@ __decorateClass([
|
|
|
162
203
|
__decorateClass([
|
|
163
204
|
(0, import_decorators.property)({ attribute: "fade-type" })
|
|
164
205
|
], DawClipElement.prototype, "fadeType", 2);
|
|
206
|
+
__decorateClass([
|
|
207
|
+
(0, import_decorators.property)({ attribute: false })
|
|
208
|
+
], DawClipElement.prototype, "midiNotes", 2);
|
|
209
|
+
__decorateClass([
|
|
210
|
+
(0, import_decorators.property)({ type: Number, attribute: "midi-channel", noAccessor: true })
|
|
211
|
+
], DawClipElement.prototype, "midiChannel", 1);
|
|
212
|
+
__decorateClass([
|
|
213
|
+
(0, import_decorators.property)({ type: Number, attribute: "midi-program", noAccessor: true })
|
|
214
|
+
], DawClipElement.prototype, "midiProgram", 1);
|
|
165
215
|
DawClipElement = __decorateClass([
|
|
166
216
|
(0, import_decorators.customElement)("daw-clip")
|
|
167
217
|
], DawClipElement);
|
|
@@ -178,6 +228,7 @@ var DawTrackElement = class extends import_lit2.LitElement {
|
|
|
178
228
|
this.pan = 0;
|
|
179
229
|
this.muted = false;
|
|
180
230
|
this.soloed = false;
|
|
231
|
+
this.renderMode = "waveform";
|
|
181
232
|
this.trackId = crypto.randomUUID();
|
|
182
233
|
// Track removal is detected by the editor's MutationObserver,
|
|
183
234
|
// not by dispatching from disconnectedCallback (detached elements
|
|
@@ -205,7 +256,7 @@ var DawTrackElement = class extends import_lit2.LitElement {
|
|
|
205
256
|
this._hasRendered = true;
|
|
206
257
|
return;
|
|
207
258
|
}
|
|
208
|
-
const trackProps = ["volume", "pan", "muted", "soloed", "src", "name"];
|
|
259
|
+
const trackProps = ["volume", "pan", "muted", "soloed", "src", "name", "renderMode"];
|
|
209
260
|
const hasTrackChange = trackProps.some((p) => changed.has(p));
|
|
210
261
|
if (hasTrackChange) {
|
|
211
262
|
this.dispatchEvent(
|
|
@@ -236,6 +287,9 @@ __decorateClass([
|
|
|
236
287
|
__decorateClass([
|
|
237
288
|
(0, import_decorators2.property)({ type: Boolean })
|
|
238
289
|
], DawTrackElement.prototype, "soloed", 2);
|
|
290
|
+
__decorateClass([
|
|
291
|
+
(0, import_decorators2.property)({ attribute: "render-mode" })
|
|
292
|
+
], DawTrackElement.prototype, "renderMode", 2);
|
|
239
293
|
DawTrackElement = __decorateClass([
|
|
240
294
|
(0, import_decorators2.customElement)("daw-track")
|
|
241
295
|
], DawTrackElement);
|
|
@@ -585,9 +639,229 @@ DawWaveformElement = __decorateClass([
|
|
|
585
639
|
(0, import_decorators3.customElement)("daw-waveform")
|
|
586
640
|
], DawWaveformElement);
|
|
587
641
|
|
|
588
|
-
// src/elements/daw-
|
|
642
|
+
// src/elements/daw-piano-roll.ts
|
|
589
643
|
var import_lit4 = require("lit");
|
|
590
644
|
var import_decorators4 = require("lit/decorators.js");
|
|
645
|
+
var MAX_CANVAS_WIDTH2 = 1e3;
|
|
646
|
+
var LAYOUT_PROPS2 = /* @__PURE__ */ new Set([
|
|
647
|
+
"length",
|
|
648
|
+
"waveHeight",
|
|
649
|
+
"samplesPerPixel",
|
|
650
|
+
"sampleRate",
|
|
651
|
+
"clipOffsetSeconds",
|
|
652
|
+
"midiNotes",
|
|
653
|
+
"selected"
|
|
654
|
+
]);
|
|
655
|
+
var DawPianoRollElement = class extends import_lit4.LitElement {
|
|
656
|
+
constructor() {
|
|
657
|
+
super(...arguments);
|
|
658
|
+
this.midiNotes = [];
|
|
659
|
+
this.length = 0;
|
|
660
|
+
this.waveHeight = 128;
|
|
661
|
+
this._samplesPerPixel = 1024;
|
|
662
|
+
this._sampleRate = 48e3;
|
|
663
|
+
this.clipOffsetSeconds = 0;
|
|
664
|
+
this.visibleStart = -Infinity;
|
|
665
|
+
this.visibleEnd = Infinity;
|
|
666
|
+
this.originX = 0;
|
|
667
|
+
this.selected = false;
|
|
668
|
+
this._rafHandle = null;
|
|
669
|
+
}
|
|
670
|
+
get samplesPerPixel() {
|
|
671
|
+
return this._samplesPerPixel;
|
|
672
|
+
}
|
|
673
|
+
set samplesPerPixel(value) {
|
|
674
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
675
|
+
console.warn("[dawcore] daw-piano-roll samplesPerPixel " + value + " is invalid \u2014 ignored");
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
const old = this._samplesPerPixel;
|
|
679
|
+
this._samplesPerPixel = value;
|
|
680
|
+
this.requestUpdate("samplesPerPixel", old);
|
|
681
|
+
}
|
|
682
|
+
get sampleRate() {
|
|
683
|
+
return this._sampleRate;
|
|
684
|
+
}
|
|
685
|
+
set sampleRate(value) {
|
|
686
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
687
|
+
console.warn("[dawcore] daw-piano-roll sampleRate " + value + " is invalid \u2014 ignored");
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const old = this._sampleRate;
|
|
691
|
+
this._sampleRate = value;
|
|
692
|
+
this.requestUpdate("sampleRate", old);
|
|
693
|
+
}
|
|
694
|
+
_scheduleDraw() {
|
|
695
|
+
if (this._rafHandle !== null) return;
|
|
696
|
+
this._rafHandle = requestAnimationFrame(() => {
|
|
697
|
+
this._rafHandle = null;
|
|
698
|
+
this._draw();
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
willUpdate(_changed) {
|
|
702
|
+
this._scheduleDraw();
|
|
703
|
+
}
|
|
704
|
+
updated(changedProperties) {
|
|
705
|
+
const needsFullDraw = [...changedProperties.keys()].some((key) => LAYOUT_PROPS2.has(key));
|
|
706
|
+
if (needsFullDraw) return;
|
|
707
|
+
if (changedProperties.has("visibleStart") || changedProperties.has("visibleEnd") || changedProperties.has("originX")) {
|
|
708
|
+
this._scheduleDraw();
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
_getPitchRange() {
|
|
712
|
+
if (this.midiNotes.length === 0) return { minMidi: 0, maxMidi: 127 };
|
|
713
|
+
let min = 127;
|
|
714
|
+
let max = 0;
|
|
715
|
+
for (const note of this.midiNotes) {
|
|
716
|
+
if (note.midi < min) min = note.midi;
|
|
717
|
+
if (note.midi > max) max = note.midi;
|
|
718
|
+
}
|
|
719
|
+
return {
|
|
720
|
+
minMidi: Math.max(0, min - 1),
|
|
721
|
+
maxMidi: Math.min(127, max + 1)
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
_getNoteColor() {
|
|
725
|
+
const cs = getComputedStyle(this);
|
|
726
|
+
const note = cs.getPropertyValue("--daw-piano-roll-note-color").trim() || "#2a7070";
|
|
727
|
+
const selectedColor = cs.getPropertyValue("--daw-piano-roll-selected-note-color").trim() || "#3d9e9e";
|
|
728
|
+
return this.selected ? selectedColor : note;
|
|
729
|
+
}
|
|
730
|
+
_draw() {
|
|
731
|
+
if (!this.shadowRoot) return;
|
|
732
|
+
const canvases = this.shadowRoot.querySelectorAll("canvas");
|
|
733
|
+
if (canvases.length === 0) return;
|
|
734
|
+
const { minMidi, maxMidi } = this._getPitchRange();
|
|
735
|
+
const noteRange = maxMidi - minMidi + 1;
|
|
736
|
+
const noteHeight = Math.max(2, this.waveHeight / noteRange);
|
|
737
|
+
const pixelsPerSecond = this.sampleRate / this.samplesPerPixel;
|
|
738
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
739
|
+
const color = this._getNoteColor();
|
|
740
|
+
for (const canvas of canvases) {
|
|
741
|
+
const chunkIdx = Number(canvas.dataset.index);
|
|
742
|
+
const chunkPixelStart = chunkIdx * MAX_CANVAS_WIDTH2;
|
|
743
|
+
const canvasWidth = canvas.width / dpr;
|
|
744
|
+
const ctx = canvas.getContext("2d");
|
|
745
|
+
if (!ctx) continue;
|
|
746
|
+
ctx.resetTransform();
|
|
747
|
+
ctx.clearRect(
|
|
748
|
+
0,
|
|
749
|
+
0,
|
|
750
|
+
canvas.width,
|
|
751
|
+
canvas.height
|
|
752
|
+
);
|
|
753
|
+
ctx.imageSmoothingEnabled = false;
|
|
754
|
+
ctx.scale(dpr, dpr);
|
|
755
|
+
const chunkStartTime = chunkPixelStart * this.samplesPerPixel / this.sampleRate;
|
|
756
|
+
const chunkEndTime = (chunkPixelStart + canvasWidth) * this.samplesPerPixel / this.sampleRate;
|
|
757
|
+
for (const note of this.midiNotes) {
|
|
758
|
+
const noteStart = note.time - this.clipOffsetSeconds;
|
|
759
|
+
const noteEnd = noteStart + note.duration;
|
|
760
|
+
if (noteEnd <= chunkStartTime || noteStart >= chunkEndTime) continue;
|
|
761
|
+
const x = noteStart * pixelsPerSecond - chunkPixelStart;
|
|
762
|
+
const w = Math.max(2, note.duration * pixelsPerSecond);
|
|
763
|
+
const y = (maxMidi - note.midi) / noteRange * this.waveHeight;
|
|
764
|
+
const alpha = 0.3 + note.velocity * 0.7;
|
|
765
|
+
ctx.fillStyle = color;
|
|
766
|
+
ctx.globalAlpha = alpha;
|
|
767
|
+
ctx.beginPath();
|
|
768
|
+
ctx.roundRect(x, y, w, noteHeight, 1);
|
|
769
|
+
ctx.fill();
|
|
770
|
+
}
|
|
771
|
+
ctx.globalAlpha = 1;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
connectedCallback() {
|
|
775
|
+
super.connectedCallback();
|
|
776
|
+
this._scheduleDraw();
|
|
777
|
+
}
|
|
778
|
+
disconnectedCallback() {
|
|
779
|
+
super.disconnectedCallback();
|
|
780
|
+
if (this._rafHandle !== null) {
|
|
781
|
+
cancelAnimationFrame(this._rafHandle);
|
|
782
|
+
this._rafHandle = null;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
render() {
|
|
786
|
+
if (this.length <= 0)
|
|
787
|
+
return import_lit4.html`<div class="container" style="width: 0; height: ${this.waveHeight}px;"></div>`;
|
|
788
|
+
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
789
|
+
const visibleIndices = getVisibleChunkIndices(
|
|
790
|
+
this.length,
|
|
791
|
+
MAX_CANVAS_WIDTH2,
|
|
792
|
+
this.visibleStart,
|
|
793
|
+
this.visibleEnd,
|
|
794
|
+
this.originX
|
|
795
|
+
);
|
|
796
|
+
return import_lit4.html`
|
|
797
|
+
<div class="container" style="width: ${this.length}px; height: ${this.waveHeight}px;">
|
|
798
|
+
${visibleIndices.map((i) => {
|
|
799
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH2;
|
|
800
|
+
const chunkWidth = Math.min(this.length - chunkLeft, MAX_CANVAS_WIDTH2);
|
|
801
|
+
return import_lit4.html`<canvas
|
|
802
|
+
data-index=${i}
|
|
803
|
+
width=${chunkWidth * dpr}
|
|
804
|
+
height=${this.waveHeight * dpr}
|
|
805
|
+
style="left: ${chunkLeft}px; width: ${chunkWidth}px; height: ${this.waveHeight}px;"
|
|
806
|
+
></canvas>`;
|
|
807
|
+
})}
|
|
808
|
+
</div>
|
|
809
|
+
`;
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
DawPianoRollElement.styles = import_lit4.css`
|
|
813
|
+
:host {
|
|
814
|
+
display: block;
|
|
815
|
+
position: relative;
|
|
816
|
+
}
|
|
817
|
+
.container {
|
|
818
|
+
position: relative;
|
|
819
|
+
background: var(--daw-piano-roll-background, #1a1a2e);
|
|
820
|
+
}
|
|
821
|
+
canvas {
|
|
822
|
+
position: absolute;
|
|
823
|
+
top: 0;
|
|
824
|
+
image-rendering: pixelated;
|
|
825
|
+
image-rendering: crisp-edges;
|
|
826
|
+
}
|
|
827
|
+
`;
|
|
828
|
+
__decorateClass([
|
|
829
|
+
(0, import_decorators4.property)({ attribute: false })
|
|
830
|
+
], DawPianoRollElement.prototype, "midiNotes", 2);
|
|
831
|
+
__decorateClass([
|
|
832
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
833
|
+
], DawPianoRollElement.prototype, "length", 2);
|
|
834
|
+
__decorateClass([
|
|
835
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
836
|
+
], DawPianoRollElement.prototype, "waveHeight", 2);
|
|
837
|
+
__decorateClass([
|
|
838
|
+
(0, import_decorators4.property)({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
839
|
+
], DawPianoRollElement.prototype, "samplesPerPixel", 1);
|
|
840
|
+
__decorateClass([
|
|
841
|
+
(0, import_decorators4.property)({ type: Number, attribute: "sample-rate", noAccessor: true })
|
|
842
|
+
], DawPianoRollElement.prototype, "sampleRate", 1);
|
|
843
|
+
__decorateClass([
|
|
844
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
845
|
+
], DawPianoRollElement.prototype, "clipOffsetSeconds", 2);
|
|
846
|
+
__decorateClass([
|
|
847
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
848
|
+
], DawPianoRollElement.prototype, "visibleStart", 2);
|
|
849
|
+
__decorateClass([
|
|
850
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
851
|
+
], DawPianoRollElement.prototype, "visibleEnd", 2);
|
|
852
|
+
__decorateClass([
|
|
853
|
+
(0, import_decorators4.property)({ type: Number, attribute: false })
|
|
854
|
+
], DawPianoRollElement.prototype, "originX", 2);
|
|
855
|
+
__decorateClass([
|
|
856
|
+
(0, import_decorators4.property)({ type: Boolean, reflect: true })
|
|
857
|
+
], DawPianoRollElement.prototype, "selected", 2);
|
|
858
|
+
DawPianoRollElement = __decorateClass([
|
|
859
|
+
(0, import_decorators4.customElement)("daw-piano-roll")
|
|
860
|
+
], DawPianoRollElement);
|
|
861
|
+
|
|
862
|
+
// src/elements/daw-playhead.ts
|
|
863
|
+
var import_lit5 = require("lit");
|
|
864
|
+
var import_decorators5 = require("lit/decorators.js");
|
|
591
865
|
|
|
592
866
|
// src/controllers/animation-controller.ts
|
|
593
867
|
var AnimationController = class {
|
|
@@ -620,14 +894,14 @@ var AnimationController = class {
|
|
|
620
894
|
};
|
|
621
895
|
|
|
622
896
|
// src/elements/daw-playhead.ts
|
|
623
|
-
var DawPlayheadElement = class extends
|
|
897
|
+
var DawPlayheadElement = class extends import_lit5.LitElement {
|
|
624
898
|
constructor() {
|
|
625
899
|
super(...arguments);
|
|
626
900
|
this._animation = new AnimationController(this);
|
|
627
901
|
this._line = null;
|
|
628
902
|
}
|
|
629
903
|
render() {
|
|
630
|
-
return
|
|
904
|
+
return import_lit5.html`<div></div>`;
|
|
631
905
|
}
|
|
632
906
|
firstUpdated() {
|
|
633
907
|
this._line = this.shadowRoot.querySelector("div");
|
|
@@ -683,7 +957,7 @@ var DawPlayheadElement = class extends import_lit4.LitElement {
|
|
|
683
957
|
}
|
|
684
958
|
}
|
|
685
959
|
};
|
|
686
|
-
DawPlayheadElement.styles =
|
|
960
|
+
DawPlayheadElement.styles = import_lit5.css`
|
|
687
961
|
:host {
|
|
688
962
|
position: absolute;
|
|
689
963
|
top: 0;
|
|
@@ -702,13 +976,13 @@ DawPlayheadElement.styles = import_lit4.css`
|
|
|
702
976
|
}
|
|
703
977
|
`;
|
|
704
978
|
DawPlayheadElement = __decorateClass([
|
|
705
|
-
(0,
|
|
979
|
+
(0, import_decorators5.customElement)("daw-playhead")
|
|
706
980
|
], DawPlayheadElement);
|
|
707
981
|
|
|
708
982
|
// src/elements/daw-transport.ts
|
|
709
|
-
var
|
|
710
|
-
var
|
|
711
|
-
var DawTransportElement = class extends
|
|
983
|
+
var import_lit6 = require("lit");
|
|
984
|
+
var import_decorators6 = require("lit/decorators.js");
|
|
985
|
+
var DawTransportElement = class extends import_lit6.LitElement {
|
|
712
986
|
constructor() {
|
|
713
987
|
super(...arguments);
|
|
714
988
|
this.for = "";
|
|
@@ -723,25 +997,25 @@ var DawTransportElement = class extends import_lit5.LitElement {
|
|
|
723
997
|
}
|
|
724
998
|
};
|
|
725
999
|
__decorateClass([
|
|
726
|
-
(0,
|
|
1000
|
+
(0, import_decorators6.property)()
|
|
727
1001
|
], DawTransportElement.prototype, "for", 2);
|
|
728
1002
|
DawTransportElement = __decorateClass([
|
|
729
|
-
(0,
|
|
1003
|
+
(0, import_decorators6.customElement)("daw-transport")
|
|
730
1004
|
], DawTransportElement);
|
|
731
1005
|
|
|
732
1006
|
// src/elements/daw-play-button.ts
|
|
733
|
-
var
|
|
734
|
-
var
|
|
1007
|
+
var import_lit8 = require("lit");
|
|
1008
|
+
var import_decorators7 = require("lit/decorators.js");
|
|
735
1009
|
|
|
736
1010
|
// src/elements/daw-transport-button.ts
|
|
737
|
-
var
|
|
738
|
-
var DawTransportButton = class extends
|
|
1011
|
+
var import_lit7 = require("lit");
|
|
1012
|
+
var DawTransportButton = class extends import_lit7.LitElement {
|
|
739
1013
|
get target() {
|
|
740
1014
|
const transport = this.closest("daw-transport");
|
|
741
1015
|
return transport?.target ?? null;
|
|
742
1016
|
}
|
|
743
1017
|
};
|
|
744
|
-
DawTransportButton.styles =
|
|
1018
|
+
DawTransportButton.styles = import_lit7.css`
|
|
745
1019
|
button {
|
|
746
1020
|
cursor: pointer;
|
|
747
1021
|
background: var(--daw-controls-background, #1a1a2e);
|
|
@@ -793,7 +1067,7 @@ var DawPlayButtonElement = class extends DawTransportButton {
|
|
|
793
1067
|
}
|
|
794
1068
|
}
|
|
795
1069
|
render() {
|
|
796
|
-
return
|
|
1070
|
+
return import_lit8.html`
|
|
797
1071
|
<button part="button" ?disabled=${this._isRecording} @click=${this._onClick}>
|
|
798
1072
|
<slot>Play</slot>
|
|
799
1073
|
</button>
|
|
@@ -811,15 +1085,15 @@ var DawPlayButtonElement = class extends DawTransportButton {
|
|
|
811
1085
|
}
|
|
812
1086
|
};
|
|
813
1087
|
__decorateClass([
|
|
814
|
-
(0,
|
|
1088
|
+
(0, import_decorators7.state)()
|
|
815
1089
|
], DawPlayButtonElement.prototype, "_isRecording", 2);
|
|
816
1090
|
DawPlayButtonElement = __decorateClass([
|
|
817
|
-
(0,
|
|
1091
|
+
(0, import_decorators7.customElement)("daw-play-button")
|
|
818
1092
|
], DawPlayButtonElement);
|
|
819
1093
|
|
|
820
1094
|
// src/elements/daw-pause-button.ts
|
|
821
|
-
var
|
|
822
|
-
var
|
|
1095
|
+
var import_lit9 = require("lit");
|
|
1096
|
+
var import_decorators8 = require("lit/decorators.js");
|
|
823
1097
|
var DawPauseButtonElement = class extends DawTransportButton {
|
|
824
1098
|
constructor() {
|
|
825
1099
|
super(...arguments);
|
|
@@ -833,6 +1107,12 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
833
1107
|
this._isRecording = false;
|
|
834
1108
|
this._isPaused = false;
|
|
835
1109
|
};
|
|
1110
|
+
this._onRecPause = () => {
|
|
1111
|
+
this._isPaused = true;
|
|
1112
|
+
};
|
|
1113
|
+
this._onRecResume = () => {
|
|
1114
|
+
this._isPaused = false;
|
|
1115
|
+
};
|
|
836
1116
|
}
|
|
837
1117
|
connectedCallback() {
|
|
838
1118
|
super.connectedCallback();
|
|
@@ -843,6 +1123,8 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
843
1123
|
target.addEventListener("daw-recording-start", this._onRecStart);
|
|
844
1124
|
target.addEventListener("daw-recording-complete", this._onRecEnd);
|
|
845
1125
|
target.addEventListener("daw-recording-error", this._onRecEnd);
|
|
1126
|
+
target.addEventListener("daw-recording-pause", this._onRecPause);
|
|
1127
|
+
target.addEventListener("daw-recording-resume", this._onRecResume);
|
|
846
1128
|
});
|
|
847
1129
|
}
|
|
848
1130
|
disconnectedCallback() {
|
|
@@ -851,11 +1133,13 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
851
1133
|
this._targetRef.removeEventListener("daw-recording-start", this._onRecStart);
|
|
852
1134
|
this._targetRef.removeEventListener("daw-recording-complete", this._onRecEnd);
|
|
853
1135
|
this._targetRef.removeEventListener("daw-recording-error", this._onRecEnd);
|
|
1136
|
+
this._targetRef.removeEventListener("daw-recording-pause", this._onRecPause);
|
|
1137
|
+
this._targetRef.removeEventListener("daw-recording-resume", this._onRecResume);
|
|
854
1138
|
this._targetRef = null;
|
|
855
1139
|
}
|
|
856
1140
|
}
|
|
857
1141
|
render() {
|
|
858
|
-
return
|
|
1142
|
+
return import_lit9.html`
|
|
859
1143
|
<button part="button" ?data-paused=${this._isPaused} @click=${this._onClick}>
|
|
860
1144
|
<slot>Pause</slot>
|
|
861
1145
|
</button>
|
|
@@ -870,15 +1154,7 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
870
1154
|
return;
|
|
871
1155
|
}
|
|
872
1156
|
if (this._isRecording) {
|
|
873
|
-
|
|
874
|
-
target.resumeRecording();
|
|
875
|
-
target.play(target.currentTime);
|
|
876
|
-
this._isPaused = false;
|
|
877
|
-
} else {
|
|
878
|
-
target.pauseRecording();
|
|
879
|
-
target.pause();
|
|
880
|
-
this._isPaused = true;
|
|
881
|
-
}
|
|
1157
|
+
target.togglePauseRecording();
|
|
882
1158
|
} else {
|
|
883
1159
|
target.pause();
|
|
884
1160
|
}
|
|
@@ -886,7 +1162,7 @@ var DawPauseButtonElement = class extends DawTransportButton {
|
|
|
886
1162
|
};
|
|
887
1163
|
DawPauseButtonElement.styles = [
|
|
888
1164
|
DawTransportButton.styles,
|
|
889
|
-
|
|
1165
|
+
import_lit9.css`
|
|
890
1166
|
button[data-paused] {
|
|
891
1167
|
background: rgba(255, 255, 255, 0.1);
|
|
892
1168
|
border-color: var(--daw-controls-text, #e0d4c8);
|
|
@@ -894,21 +1170,21 @@ DawPauseButtonElement.styles = [
|
|
|
894
1170
|
`
|
|
895
1171
|
];
|
|
896
1172
|
__decorateClass([
|
|
897
|
-
(0,
|
|
1173
|
+
(0, import_decorators8.state)()
|
|
898
1174
|
], DawPauseButtonElement.prototype, "_isPaused", 2);
|
|
899
1175
|
__decorateClass([
|
|
900
|
-
(0,
|
|
1176
|
+
(0, import_decorators8.state)()
|
|
901
1177
|
], DawPauseButtonElement.prototype, "_isRecording", 2);
|
|
902
1178
|
DawPauseButtonElement = __decorateClass([
|
|
903
|
-
(0,
|
|
1179
|
+
(0, import_decorators8.customElement)("daw-pause-button")
|
|
904
1180
|
], DawPauseButtonElement);
|
|
905
1181
|
|
|
906
1182
|
// src/elements/daw-stop-button.ts
|
|
907
|
-
var
|
|
908
|
-
var
|
|
1183
|
+
var import_lit10 = require("lit");
|
|
1184
|
+
var import_decorators9 = require("lit/decorators.js");
|
|
909
1185
|
var DawStopButtonElement = class extends DawTransportButton {
|
|
910
1186
|
render() {
|
|
911
|
-
return
|
|
1187
|
+
return import_lit10.html`
|
|
912
1188
|
<button part="button" @click=${this._onClick}>
|
|
913
1189
|
<slot>Stop</slot>
|
|
914
1190
|
</button>
|
|
@@ -923,18 +1199,31 @@ var DawStopButtonElement = class extends DawTransportButton {
|
|
|
923
1199
|
return;
|
|
924
1200
|
}
|
|
925
1201
|
if (target.isRecording) {
|
|
926
|
-
target.stopRecording()
|
|
1202
|
+
target.stopRecording().catch((err) => {
|
|
1203
|
+
console.warn("[dawcore] stopRecording failed: " + String(err));
|
|
1204
|
+
}).then(() => {
|
|
1205
|
+
try {
|
|
1206
|
+
target.stop();
|
|
1207
|
+
} catch (err) {
|
|
1208
|
+
console.warn("[dawcore] stop after stopRecording failed: " + String(err));
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
} else {
|
|
1212
|
+
try {
|
|
1213
|
+
target.stop();
|
|
1214
|
+
} catch (err) {
|
|
1215
|
+
console.warn("[dawcore] stop failed: " + String(err));
|
|
1216
|
+
}
|
|
927
1217
|
}
|
|
928
|
-
target.stop();
|
|
929
1218
|
}
|
|
930
1219
|
};
|
|
931
1220
|
DawStopButtonElement = __decorateClass([
|
|
932
|
-
(0,
|
|
1221
|
+
(0, import_decorators9.customElement)("daw-stop-button")
|
|
933
1222
|
], DawStopButtonElement);
|
|
934
1223
|
|
|
935
1224
|
// src/elements/daw-editor.ts
|
|
936
|
-
var
|
|
937
|
-
var
|
|
1225
|
+
var import_lit14 = require("lit");
|
|
1226
|
+
var import_decorators12 = require("lit/decorators.js");
|
|
938
1227
|
|
|
939
1228
|
// src/types.ts
|
|
940
1229
|
function isDomClip(desc) {
|
|
@@ -1414,9 +1703,9 @@ var PeakPipeline = class {
|
|
|
1414
1703
|
};
|
|
1415
1704
|
|
|
1416
1705
|
// src/elements/daw-track-controls.ts
|
|
1417
|
-
var
|
|
1418
|
-
var
|
|
1419
|
-
var DawTrackControlsElement = class extends
|
|
1706
|
+
var import_lit11 = require("lit");
|
|
1707
|
+
var import_decorators10 = require("lit/decorators.js");
|
|
1708
|
+
var DawTrackControlsElement = class extends import_lit11.LitElement {
|
|
1420
1709
|
constructor() {
|
|
1421
1710
|
super(...arguments);
|
|
1422
1711
|
this.trackId = null;
|
|
@@ -1464,7 +1753,7 @@ var DawTrackControlsElement = class extends import_lit10.LitElement {
|
|
|
1464
1753
|
const volPercent = Math.round(this.volume * 100);
|
|
1465
1754
|
const panPercent = Math.round(Math.abs(this.pan) * 100);
|
|
1466
1755
|
const panDisplay = this.pan === 0 ? "C" : (this.pan > 0 ? "R" : "L") + panPercent;
|
|
1467
|
-
return
|
|
1756
|
+
return import_lit11.html`
|
|
1468
1757
|
<div class="header">
|
|
1469
1758
|
<span class="name" title=${this.trackName}>${this.trackName || "Untitled"}</span>
|
|
1470
1759
|
<button class="remove-btn" @click=${this._onRemoveClick} title="Remove track">
|
|
@@ -1514,7 +1803,7 @@ var DawTrackControlsElement = class extends import_lit10.LitElement {
|
|
|
1514
1803
|
`;
|
|
1515
1804
|
}
|
|
1516
1805
|
};
|
|
1517
|
-
DawTrackControlsElement.styles =
|
|
1806
|
+
DawTrackControlsElement.styles = import_lit11.css`
|
|
1518
1807
|
:host {
|
|
1519
1808
|
display: flex;
|
|
1520
1809
|
flex-direction: column;
|
|
@@ -1648,30 +1937,30 @@ DawTrackControlsElement.styles = import_lit10.css`
|
|
|
1648
1937
|
}
|
|
1649
1938
|
`;
|
|
1650
1939
|
__decorateClass([
|
|
1651
|
-
(0,
|
|
1940
|
+
(0, import_decorators10.property)({ attribute: false })
|
|
1652
1941
|
], DawTrackControlsElement.prototype, "trackId", 2);
|
|
1653
1942
|
__decorateClass([
|
|
1654
|
-
(0,
|
|
1943
|
+
(0, import_decorators10.property)({ attribute: false })
|
|
1655
1944
|
], DawTrackControlsElement.prototype, "trackName", 2);
|
|
1656
1945
|
__decorateClass([
|
|
1657
|
-
(0,
|
|
1946
|
+
(0, import_decorators10.property)({ type: Number, attribute: false })
|
|
1658
1947
|
], DawTrackControlsElement.prototype, "volume", 2);
|
|
1659
1948
|
__decorateClass([
|
|
1660
|
-
(0,
|
|
1949
|
+
(0, import_decorators10.property)({ type: Number, attribute: false })
|
|
1661
1950
|
], DawTrackControlsElement.prototype, "pan", 2);
|
|
1662
1951
|
__decorateClass([
|
|
1663
|
-
(0,
|
|
1952
|
+
(0, import_decorators10.property)({ type: Boolean, attribute: false })
|
|
1664
1953
|
], DawTrackControlsElement.prototype, "muted", 2);
|
|
1665
1954
|
__decorateClass([
|
|
1666
|
-
(0,
|
|
1955
|
+
(0, import_decorators10.property)({ type: Boolean, attribute: false })
|
|
1667
1956
|
], DawTrackControlsElement.prototype, "soloed", 2);
|
|
1668
1957
|
DawTrackControlsElement = __decorateClass([
|
|
1669
|
-
(0,
|
|
1958
|
+
(0, import_decorators10.customElement)("daw-track-controls")
|
|
1670
1959
|
], DawTrackControlsElement);
|
|
1671
1960
|
|
|
1672
1961
|
// src/elements/daw-grid.ts
|
|
1673
|
-
var
|
|
1674
|
-
var
|
|
1962
|
+
var import_lit12 = require("lit");
|
|
1963
|
+
var import_decorators11 = require("lit/decorators.js");
|
|
1675
1964
|
var import_core2 = require("@waveform-playlist/core");
|
|
1676
1965
|
|
|
1677
1966
|
// src/utils/musical-tick-cache.ts
|
|
@@ -1702,8 +1991,8 @@ function getCachedMusicalTicks(params) {
|
|
|
1702
1991
|
}
|
|
1703
1992
|
|
|
1704
1993
|
// src/elements/daw-grid.ts
|
|
1705
|
-
var
|
|
1706
|
-
var DawGridElement = class extends
|
|
1994
|
+
var MAX_CANVAS_WIDTH3 = 1e3;
|
|
1995
|
+
var DawGridElement = class extends import_lit12.LitElement {
|
|
1707
1996
|
constructor() {
|
|
1708
1997
|
super(...arguments);
|
|
1709
1998
|
this.ticksPerPixel = 24;
|
|
@@ -1731,25 +2020,25 @@ var DawGridElement = class extends import_lit11.LitElement {
|
|
|
1731
2020
|
}
|
|
1732
2021
|
}
|
|
1733
2022
|
render() {
|
|
1734
|
-
if (!this._tickData) return
|
|
2023
|
+
if (!this._tickData) return import_lit12.html``;
|
|
1735
2024
|
const totalWidth = this.length;
|
|
1736
2025
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
1737
2026
|
const indices = getVisibleChunkIndices(
|
|
1738
2027
|
totalWidth,
|
|
1739
|
-
|
|
2028
|
+
MAX_CANVAS_WIDTH3,
|
|
1740
2029
|
this.visibleStart,
|
|
1741
2030
|
this.visibleEnd
|
|
1742
2031
|
);
|
|
1743
|
-
return
|
|
2032
|
+
return import_lit12.html`
|
|
1744
2033
|
<div class="container" style="width: ${totalWidth}px; height: ${this.height}px;">
|
|
1745
2034
|
${indices.map((i) => {
|
|
1746
|
-
const width = Math.min(
|
|
1747
|
-
return
|
|
2035
|
+
const width = Math.min(MAX_CANVAS_WIDTH3, totalWidth - i * MAX_CANVAS_WIDTH3);
|
|
2036
|
+
return import_lit12.html`
|
|
1748
2037
|
<canvas
|
|
1749
2038
|
data-index=${i}
|
|
1750
2039
|
width=${width * dpr}
|
|
1751
2040
|
height=${this.height * dpr}
|
|
1752
|
-
style="left: ${i *
|
|
2041
|
+
style="left: ${i * MAX_CANVAS_WIDTH3}px; width: ${width}px; height: ${this.height}px;"
|
|
1753
2042
|
></canvas>
|
|
1754
2043
|
`;
|
|
1755
2044
|
})}
|
|
@@ -1773,8 +2062,8 @@ var DawGridElement = class extends import_lit11.LitElement {
|
|
|
1773
2062
|
const idx = Number(canvas.dataset.index);
|
|
1774
2063
|
const ctx = canvas.getContext("2d");
|
|
1775
2064
|
if (!ctx) continue;
|
|
1776
|
-
const chunkLeft = idx *
|
|
1777
|
-
const canvasWidth = Math.min(
|
|
2065
|
+
const chunkLeft = idx * MAX_CANVAS_WIDTH3;
|
|
2066
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH3, this.length - chunkLeft);
|
|
1778
2067
|
ctx.resetTransform();
|
|
1779
2068
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1780
2069
|
ctx.scale(dpr, dpr);
|
|
@@ -1805,7 +2094,7 @@ var DawGridElement = class extends import_lit11.LitElement {
|
|
|
1805
2094
|
}
|
|
1806
2095
|
}
|
|
1807
2096
|
};
|
|
1808
|
-
DawGridElement.styles =
|
|
2097
|
+
DawGridElement.styles = import_lit12.css`
|
|
1809
2098
|
:host {
|
|
1810
2099
|
display: block;
|
|
1811
2100
|
position: absolute;
|
|
@@ -1823,33 +2112,33 @@ DawGridElement.styles = import_lit11.css`
|
|
|
1823
2112
|
}
|
|
1824
2113
|
`;
|
|
1825
2114
|
__decorateClass([
|
|
1826
|
-
(0,
|
|
2115
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1827
2116
|
], DawGridElement.prototype, "ticksPerPixel", 2);
|
|
1828
2117
|
__decorateClass([
|
|
1829
|
-
(0,
|
|
2118
|
+
(0, import_decorators11.property)({ attribute: false })
|
|
1830
2119
|
], DawGridElement.prototype, "meterEntries", 2);
|
|
1831
2120
|
__decorateClass([
|
|
1832
|
-
(0,
|
|
2121
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1833
2122
|
], DawGridElement.prototype, "ppqn", 2);
|
|
1834
2123
|
__decorateClass([
|
|
1835
|
-
(0,
|
|
2124
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1836
2125
|
], DawGridElement.prototype, "visibleStart", 2);
|
|
1837
2126
|
__decorateClass([
|
|
1838
|
-
(0,
|
|
2127
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1839
2128
|
], DawGridElement.prototype, "visibleEnd", 2);
|
|
1840
2129
|
__decorateClass([
|
|
1841
|
-
(0,
|
|
2130
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1842
2131
|
], DawGridElement.prototype, "length", 2);
|
|
1843
2132
|
__decorateClass([
|
|
1844
|
-
(0,
|
|
2133
|
+
(0, import_decorators11.property)({ type: Number, attribute: false })
|
|
1845
2134
|
], DawGridElement.prototype, "height", 2);
|
|
1846
2135
|
DawGridElement = __decorateClass([
|
|
1847
|
-
(0,
|
|
2136
|
+
(0, import_decorators11.customElement)("daw-grid")
|
|
1848
2137
|
], DawGridElement);
|
|
1849
2138
|
|
|
1850
2139
|
// src/styles/theme.ts
|
|
1851
|
-
var
|
|
1852
|
-
var hostStyles =
|
|
2140
|
+
var import_lit13 = require("lit");
|
|
2141
|
+
var hostStyles = import_lit13.css`
|
|
1853
2142
|
:host {
|
|
1854
2143
|
--daw-wave-color: #c49a6c;
|
|
1855
2144
|
--daw-progress-color: #63c75f;
|
|
@@ -1865,7 +2154,7 @@ var hostStyles = import_lit12.css`
|
|
|
1865
2154
|
--daw-clip-header-text: #e0d4c8;
|
|
1866
2155
|
}
|
|
1867
2156
|
`;
|
|
1868
|
-
var clipStyles =
|
|
2157
|
+
var clipStyles = import_lit13.css`
|
|
1869
2158
|
.clip-container {
|
|
1870
2159
|
position: absolute;
|
|
1871
2160
|
overflow: hidden;
|
|
@@ -2110,6 +2399,9 @@ var RecordingController = class {
|
|
|
2110
2399
|
constructor(host) {
|
|
2111
2400
|
this._sessions = /* @__PURE__ */ new Map();
|
|
2112
2401
|
this._workletLoadedCtx = null;
|
|
2402
|
+
/** Tracks worklet pause state explicitly so external consumers (editor,
|
|
2403
|
+
* pause button, spacebar) can share one source of truth. */
|
|
2404
|
+
this._isPaused = false;
|
|
2113
2405
|
this._host = host;
|
|
2114
2406
|
host.addController(this);
|
|
2115
2407
|
}
|
|
@@ -2124,6 +2416,9 @@ var RecordingController = class {
|
|
|
2124
2416
|
get isRecording() {
|
|
2125
2417
|
return this._sessions.size > 0;
|
|
2126
2418
|
}
|
|
2419
|
+
get isPaused() {
|
|
2420
|
+
return this._isPaused && this._sessions.size > 0;
|
|
2421
|
+
}
|
|
2127
2422
|
getSession(trackId) {
|
|
2128
2423
|
return this._sessions.get(trackId);
|
|
2129
2424
|
}
|
|
@@ -2196,7 +2491,9 @@ var RecordingController = class {
|
|
|
2196
2491
|
latencySamples,
|
|
2197
2492
|
wasOverdub: options.overdub ?? false,
|
|
2198
2493
|
_onTrackEnded: onTrackEnded,
|
|
2199
|
-
_audioTrack: audioTrack
|
|
2494
|
+
_audioTrack: audioTrack,
|
|
2495
|
+
stopAckResolve: null,
|
|
2496
|
+
stopping: false
|
|
2200
2497
|
};
|
|
2201
2498
|
this._sessions.set(trackId, session);
|
|
2202
2499
|
workletNode.port.onmessage = (e) => {
|
|
@@ -2234,25 +2531,69 @@ var RecordingController = class {
|
|
|
2234
2531
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2235
2532
|
if (!id) return;
|
|
2236
2533
|
const session = this._sessions.get(id);
|
|
2237
|
-
if (!session) return;
|
|
2534
|
+
if (!session || session.stopping) return;
|
|
2238
2535
|
session.workletNode.port.postMessage({ command: "pause" });
|
|
2536
|
+
this._isPaused = true;
|
|
2537
|
+
this._host.dispatchEvent(
|
|
2538
|
+
new CustomEvent("daw-recording-pause", {
|
|
2539
|
+
bubbles: true,
|
|
2540
|
+
composed: true,
|
|
2541
|
+
detail: { trackId: id }
|
|
2542
|
+
})
|
|
2543
|
+
);
|
|
2239
2544
|
}
|
|
2240
2545
|
resumeRecording(trackId) {
|
|
2241
2546
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2242
2547
|
if (!id) return;
|
|
2243
2548
|
const session = this._sessions.get(id);
|
|
2244
|
-
if (!session) return;
|
|
2549
|
+
if (!session || session.stopping) return;
|
|
2245
2550
|
session.workletNode.port.postMessage({ command: "resume" });
|
|
2551
|
+
this._isPaused = false;
|
|
2552
|
+
this._host.dispatchEvent(
|
|
2553
|
+
new CustomEvent("daw-recording-resume", {
|
|
2554
|
+
bubbles: true,
|
|
2555
|
+
composed: true,
|
|
2556
|
+
detail: { trackId: id }
|
|
2557
|
+
})
|
|
2558
|
+
);
|
|
2246
2559
|
}
|
|
2247
|
-
stopRecording(trackId) {
|
|
2560
|
+
async stopRecording(trackId) {
|
|
2248
2561
|
const id = trackId ?? [...this._sessions.keys()][0];
|
|
2249
2562
|
if (!id) return;
|
|
2250
2563
|
const session = this._sessions.get(id);
|
|
2251
2564
|
if (!session) return;
|
|
2565
|
+
const wasPaused = this._isPaused;
|
|
2566
|
+
this._isPaused = false;
|
|
2567
|
+
session.stopping = true;
|
|
2252
2568
|
if (session.wasOverdub && typeof this._host.stop === "function") {
|
|
2253
2569
|
this._host.stop();
|
|
2254
2570
|
}
|
|
2255
|
-
|
|
2571
|
+
if (wasPaused) {
|
|
2572
|
+
session.workletNode.port.postMessage({ command: "stop" });
|
|
2573
|
+
} else {
|
|
2574
|
+
const stopAck = new Promise((resolve) => {
|
|
2575
|
+
session.stopAckResolve = resolve;
|
|
2576
|
+
});
|
|
2577
|
+
let timeoutId;
|
|
2578
|
+
const timeout = new Promise((resolve) => {
|
|
2579
|
+
timeoutId = setTimeout(resolve, 1e3);
|
|
2580
|
+
});
|
|
2581
|
+
session.workletNode.port.postMessage({ command: "stop" });
|
|
2582
|
+
await Promise.race([stopAck, timeout]);
|
|
2583
|
+
clearTimeout(timeoutId);
|
|
2584
|
+
session.stopAckResolve = null;
|
|
2585
|
+
let lastSamples = -1;
|
|
2586
|
+
let stable = 0;
|
|
2587
|
+
for (let i = 0; i < 50; i++) {
|
|
2588
|
+
if (session.totalSamples === lastSamples) {
|
|
2589
|
+
if (++stable >= 3) break;
|
|
2590
|
+
} else {
|
|
2591
|
+
stable = 0;
|
|
2592
|
+
lastSamples = session.totalSamples;
|
|
2593
|
+
}
|
|
2594
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2256
2597
|
session.source.disconnect();
|
|
2257
2598
|
session.workletNode.disconnect();
|
|
2258
2599
|
this._removeTrackEndedListener(session);
|
|
@@ -2324,8 +2665,20 @@ var RecordingController = class {
|
|
|
2324
2665
|
_onWorkletMessage(trackId, data) {
|
|
2325
2666
|
const session = this._sessions.get(trackId);
|
|
2326
2667
|
if (!session) return;
|
|
2327
|
-
const { channels } = data;
|
|
2328
|
-
|
|
2668
|
+
const { channels, done } = data;
|
|
2669
|
+
try {
|
|
2670
|
+
const hasSamples = !!(channels && channels.length > 0 && channels[0] && channels[0].length > 0);
|
|
2671
|
+
if (!hasSamples) return;
|
|
2672
|
+
this._processWorkletSamples(trackId, session, channels);
|
|
2673
|
+
} finally {
|
|
2674
|
+
if (done && session.stopAckResolve) {
|
|
2675
|
+
const resolve = session.stopAckResolve;
|
|
2676
|
+
session.stopAckResolve = null;
|
|
2677
|
+
resolve();
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
_processWorkletSamples(trackId, session, channels) {
|
|
2329
2682
|
const samplesProcessedBefore = session.totalSamples;
|
|
2330
2683
|
for (let ch = 0; ch < session.channelCount; ch++) {
|
|
2331
2684
|
if (channels[ch]) {
|
|
@@ -2333,6 +2686,7 @@ var RecordingController = class {
|
|
|
2333
2686
|
}
|
|
2334
2687
|
}
|
|
2335
2688
|
session.totalSamples += channels[0].length;
|
|
2689
|
+
if (session.stopAckResolve !== null) return;
|
|
2336
2690
|
for (let ch = 0; ch < session.channelCount; ch++) {
|
|
2337
2691
|
if (!channels[ch]) continue;
|
|
2338
2692
|
const oldPeakCount = Math.floor(session.peaks[ch].length / 2);
|
|
@@ -2667,6 +3021,7 @@ var ClipPointerHandler = class {
|
|
|
2667
3021
|
const trackId = boundary.dataset.trackId;
|
|
2668
3022
|
const edge = boundary.dataset.boundaryEdge;
|
|
2669
3023
|
if (!clipId || !trackId || edge !== "left" && edge !== "right") return false;
|
|
3024
|
+
if (this._host.isMidiClip(trackId, clipId)) return true;
|
|
2670
3025
|
this._beginDrag(edge === "left" ? "trim-left" : "trim-right", clipId, trackId, e);
|
|
2671
3026
|
this._boundaryEl = boundary;
|
|
2672
3027
|
return true;
|
|
@@ -2960,6 +3315,7 @@ async function loadFiles(host, files) {
|
|
|
2960
3315
|
pan: 0,
|
|
2961
3316
|
muted: false,
|
|
2962
3317
|
soloed: false,
|
|
3318
|
+
renderMode: "waveform",
|
|
2963
3319
|
clips: [
|
|
2964
3320
|
{
|
|
2965
3321
|
kind: "drop",
|
|
@@ -2972,7 +3328,10 @@ async function loadFiles(host, files) {
|
|
|
2972
3328
|
name,
|
|
2973
3329
|
fadeIn: 0,
|
|
2974
3330
|
fadeOut: 0,
|
|
2975
|
-
fadeType: "linear"
|
|
3331
|
+
fadeType: "linear",
|
|
3332
|
+
midiNotes: null,
|
|
3333
|
+
midiChannel: null,
|
|
3334
|
+
midiProgram: null
|
|
2976
3335
|
}
|
|
2977
3336
|
]
|
|
2978
3337
|
});
|
|
@@ -3059,7 +3418,10 @@ function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamp
|
|
|
3059
3418
|
name: "Recording",
|
|
3060
3419
|
fadeIn: 0,
|
|
3061
3420
|
fadeOut: 0,
|
|
3062
|
-
fadeType: "linear"
|
|
3421
|
+
fadeType: "linear",
|
|
3422
|
+
midiNotes: null,
|
|
3423
|
+
midiChannel: null,
|
|
3424
|
+
midiProgram: null
|
|
3063
3425
|
};
|
|
3064
3426
|
host._tracks = new Map(host._tracks).set(trackId, {
|
|
3065
3427
|
...desc,
|
|
@@ -3118,7 +3480,10 @@ function canSplitAtTime(host, time) {
|
|
|
3118
3480
|
const track = state5.tracks.find((t) => t.id === state5.selectedTrackId);
|
|
3119
3481
|
if (!track) return false;
|
|
3120
3482
|
const atSample = Math.round(time * host.effectiveSampleRate);
|
|
3121
|
-
|
|
3483
|
+
const clip = findClipAtSample(track.clips, atSample);
|
|
3484
|
+
if (!clip) return false;
|
|
3485
|
+
if (clip.midiNotes != null) return false;
|
|
3486
|
+
return true;
|
|
3122
3487
|
}
|
|
3123
3488
|
function performSplit(host, time) {
|
|
3124
3489
|
const { engine } = host;
|
|
@@ -3273,7 +3638,7 @@ async function loadWaveformDataFromUrl(src) {
|
|
|
3273
3638
|
|
|
3274
3639
|
// src/elements/daw-editor.ts
|
|
3275
3640
|
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();";
|
|
3276
|
-
var DawEditorElement = class extends
|
|
3641
|
+
var DawEditorElement = class extends import_lit14.LitElement {
|
|
3277
3642
|
constructor() {
|
|
3278
3643
|
super(...arguments);
|
|
3279
3644
|
this._samplesPerPixel = 1024;
|
|
@@ -3432,7 +3797,10 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
3432
3797
|
name: clipEl.name,
|
|
3433
3798
|
fadeIn: clipEl.fadeIn,
|
|
3434
3799
|
fadeOut: clipEl.fadeOut,
|
|
3435
|
-
fadeType: clipEl.fadeType
|
|
3800
|
+
fadeType: clipEl.fadeType,
|
|
3801
|
+
midiNotes: clipEl.midiNotes,
|
|
3802
|
+
midiChannel: clipEl.midiChannel,
|
|
3803
|
+
midiProgram: clipEl.midiProgram
|
|
3436
3804
|
};
|
|
3437
3805
|
this._loadAndAppendClip(trackId, clipDesc);
|
|
3438
3806
|
};
|
|
@@ -3483,6 +3851,9 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
3483
3851
|
};
|
|
3484
3852
|
// --- Recording ---
|
|
3485
3853
|
this.recordingStream = null;
|
|
3854
|
+
/** Set in togglePauseRecording when Transport is paused alongside the
|
|
3855
|
+
* worklet, so resume can restart it. Cleared on resume and on stop. */
|
|
3856
|
+
this._wasPlayingDuringRecording = false;
|
|
3486
3857
|
}
|
|
3487
3858
|
get samplesPerPixel() {
|
|
3488
3859
|
return this._samplesPerPixel;
|
|
@@ -3582,6 +3953,17 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
3582
3953
|
);
|
|
3583
3954
|
return result.get(clipId) ?? null;
|
|
3584
3955
|
}
|
|
3956
|
+
/**
|
|
3957
|
+
* Returns true if the clip is a MIDI clip (has midiNotes).
|
|
3958
|
+
* Used by ClipPointerHandler to make trim handles inert for MIDI clips.
|
|
3959
|
+
* Returns false for unknown track/clip IDs (defensive).
|
|
3960
|
+
*/
|
|
3961
|
+
isMidiClip(trackId, clipId) {
|
|
3962
|
+
const track = this._engineTracks.get(trackId);
|
|
3963
|
+
if (!track) return false;
|
|
3964
|
+
const clip = track.clips.find((c) => c.id === clipId);
|
|
3965
|
+
return clip?.midiNotes != null;
|
|
3966
|
+
}
|
|
3585
3967
|
get effectiveSampleRate() {
|
|
3586
3968
|
return this._resolvedSampleRate ?? this.sampleRate;
|
|
3587
3969
|
}
|
|
@@ -3931,6 +4313,65 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
3931
4313
|
}
|
|
3932
4314
|
return clip;
|
|
3933
4315
|
}
|
|
4316
|
+
/**
|
|
4317
|
+
* Filter MIDI notes to only those with finite, in-range fields. Logs a
|
|
4318
|
+
* warning for each dropped note. Used by _buildMidiClip and the
|
|
4319
|
+
* _applyClipUpdate MIDI branch to prevent NaN propagation through the
|
|
4320
|
+
* timeline.
|
|
4321
|
+
*/
|
|
4322
|
+
_validMidiNotes(notes) {
|
|
4323
|
+
return notes.filter((n) => {
|
|
4324
|
+
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;
|
|
4325
|
+
if (!ok) {
|
|
4326
|
+
console.warn("[dawcore] dropping malformed MIDI note: " + JSON.stringify(n));
|
|
4327
|
+
}
|
|
4328
|
+
return ok;
|
|
4329
|
+
});
|
|
4330
|
+
}
|
|
4331
|
+
/**
|
|
4332
|
+
* A clip descriptor is treated as MIDI when it has no audio src.
|
|
4333
|
+
* Includes placeholder MIDI clips (no notes, no duration yet — registered
|
|
4334
|
+
* with a 1s default span; notes upgrade via _applyClipUpdate). Warns when
|
|
4335
|
+
* a clip ambiguously has both src and midiNotes — the audio path runs
|
|
4336
|
+
* and notes would be silently ignored.
|
|
4337
|
+
*/
|
|
4338
|
+
_isMidiDescriptor(clipDesc) {
|
|
4339
|
+
if (clipDesc.src) {
|
|
4340
|
+
if (clipDesc.midiNotes != null) {
|
|
4341
|
+
console.warn(
|
|
4342
|
+
'[dawcore] clip "' + (clipDesc.name || (isDomClip(clipDesc) ? clipDesc.clipId : "?")) + '" has both src and midiNotes \u2014 treating as audio (notes will be ignored)'
|
|
4343
|
+
);
|
|
4344
|
+
}
|
|
4345
|
+
return false;
|
|
4346
|
+
}
|
|
4347
|
+
return true;
|
|
4348
|
+
}
|
|
4349
|
+
/**
|
|
4350
|
+
* Build an engine clip from a MIDI clip descriptor. Always returns a clip
|
|
4351
|
+
* — empty notes / no declared duration get a 1-second placeholder span so
|
|
4352
|
+
* the clip is reachable via `engine.updateTrack` once notes arrive.
|
|
4353
|
+
*/
|
|
4354
|
+
_buildMidiClip(clipDesc) {
|
|
4355
|
+
const sr = this.effectiveSampleRate;
|
|
4356
|
+
const notes = this._validMidiNotes(clipDesc.midiNotes ?? []);
|
|
4357
|
+
const noteSpanSeconds = notes.length ? notes.reduce((max, n) => Math.max(max, n.time + n.duration), 0) : 0;
|
|
4358
|
+
const sourceDurationSamples = Math.ceil(Math.max(noteSpanSeconds, clipDesc.duration, 1) * sr);
|
|
4359
|
+
const requestedDurationSamples = clipDesc.duration > 0 ? Math.round(clipDesc.duration * sr) : sourceDurationSamples;
|
|
4360
|
+
const clip = (0, import_core8.createClip)({
|
|
4361
|
+
startSample: Math.round(clipDesc.start * sr),
|
|
4362
|
+
durationSamples: requestedDurationSamples,
|
|
4363
|
+
offsetSamples: Math.round(clipDesc.offset * sr),
|
|
4364
|
+
sampleRate: sr,
|
|
4365
|
+
sourceDurationSamples,
|
|
4366
|
+
gain: clipDesc.gain,
|
|
4367
|
+
name: clipDesc.name,
|
|
4368
|
+
midiNotes: notes,
|
|
4369
|
+
midiChannel: clipDesc.midiChannel ?? void 0,
|
|
4370
|
+
midiProgram: clipDesc.midiProgram ?? void 0
|
|
4371
|
+
});
|
|
4372
|
+
if (isDomClip(clipDesc)) clip.id = clipDesc.clipId;
|
|
4373
|
+
return clip;
|
|
4374
|
+
}
|
|
3934
4375
|
/** Remove a single clip from all per-clip caches. Used by error rollbacks. */
|
|
3935
4376
|
_purgeClipCaches(clipId) {
|
|
3936
4377
|
const nextBuffers = new Map(this._clipBuffers);
|
|
@@ -3968,6 +4409,34 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
3968
4409
|
}
|
|
3969
4410
|
const oldClip = t.clips[idx];
|
|
3970
4411
|
const sr = oldClip.sampleRate ?? this.effectiveSampleRate;
|
|
4412
|
+
const isMidiNow = clipEl.midiNotes != null;
|
|
4413
|
+
const wasMidi = oldClip.midiNotes != null;
|
|
4414
|
+
if (isMidiNow || wasMidi) {
|
|
4415
|
+
const notes = this._validMidiNotes(clipEl.midiNotes ?? []);
|
|
4416
|
+
const noteSpanSeconds = notes.length ? notes.reduce((max, n) => Math.max(max, n.time + n.duration), 0) : 0;
|
|
4417
|
+
const sourceDurationSamples = Math.ceil(Math.max(noteSpanSeconds, clipEl.duration, 1) * sr);
|
|
4418
|
+
const requestedDurationSamples = clipEl.duration > 0 ? Math.round(clipEl.duration * sr) : sourceDurationSamples;
|
|
4419
|
+
const updatedClip2 = {
|
|
4420
|
+
...oldClip,
|
|
4421
|
+
audioBuffer: void 0,
|
|
4422
|
+
startSample: Math.round(clipEl.start * sr),
|
|
4423
|
+
offsetSamples: Math.round(clipEl.offset * sr),
|
|
4424
|
+
durationSamples: requestedDurationSamples,
|
|
4425
|
+
sourceDurationSamples,
|
|
4426
|
+
gain: clipEl.gain,
|
|
4427
|
+
name: clipEl.name || oldClip.name,
|
|
4428
|
+
midiNotes: notes,
|
|
4429
|
+
midiChannel: clipEl.midiChannel ?? void 0,
|
|
4430
|
+
midiProgram: clipEl.midiProgram ?? void 0
|
|
4431
|
+
};
|
|
4432
|
+
const updatedClips2 = [...t.clips];
|
|
4433
|
+
updatedClips2[idx] = updatedClip2;
|
|
4434
|
+
const updatedTrack2 = { ...t, clips: updatedClips2 };
|
|
4435
|
+
this._engineTracks = new Map(this._engineTracks).set(trackId, updatedTrack2);
|
|
4436
|
+
this._purgeClipCaches(clipId);
|
|
4437
|
+
this._commitTrackChange(trackId, updatedTrack2);
|
|
4438
|
+
return;
|
|
4439
|
+
}
|
|
3971
4440
|
const newStartSample = Math.round(clipEl.start * sr);
|
|
3972
4441
|
const newDurationSamples = clipEl.duration > 0 ? Math.round(clipEl.duration * sr) : oldClip.durationSamples;
|
|
3973
4442
|
const newOffsetSamples = Math.round(clipEl.offset * sr);
|
|
@@ -4044,7 +4513,10 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4044
4513
|
name: trackEl.name || "",
|
|
4045
4514
|
fadeIn: 0,
|
|
4046
4515
|
fadeOut: 0,
|
|
4047
|
-
fadeType: "linear"
|
|
4516
|
+
fadeType: "linear",
|
|
4517
|
+
midiNotes: null,
|
|
4518
|
+
midiChannel: null,
|
|
4519
|
+
midiProgram: null
|
|
4048
4520
|
});
|
|
4049
4521
|
} else {
|
|
4050
4522
|
for (const clipEl of clipEls) {
|
|
@@ -4060,7 +4532,10 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4060
4532
|
name: clipEl.name,
|
|
4061
4533
|
fadeIn: clipEl.fadeIn,
|
|
4062
4534
|
fadeOut: clipEl.fadeOut,
|
|
4063
|
-
fadeType: clipEl.fadeType
|
|
4535
|
+
fadeType: clipEl.fadeType,
|
|
4536
|
+
midiNotes: clipEl.midiNotes,
|
|
4537
|
+
midiChannel: clipEl.midiChannel,
|
|
4538
|
+
midiProgram: clipEl.midiProgram
|
|
4064
4539
|
});
|
|
4065
4540
|
}
|
|
4066
4541
|
}
|
|
@@ -4071,6 +4546,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4071
4546
|
pan: trackEl.pan,
|
|
4072
4547
|
muted: trackEl.muted,
|
|
4073
4548
|
soloed: trackEl.soloed,
|
|
4549
|
+
renderMode: trackEl.renderMode,
|
|
4074
4550
|
clips
|
|
4075
4551
|
};
|
|
4076
4552
|
}
|
|
@@ -4079,7 +4555,10 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4079
4555
|
try {
|
|
4080
4556
|
const clips = [];
|
|
4081
4557
|
for (const clipDesc of descriptor.clips) {
|
|
4082
|
-
if (
|
|
4558
|
+
if (this._isMidiDescriptor(clipDesc)) {
|
|
4559
|
+
clips.push(this._buildMidiClip(clipDesc));
|
|
4560
|
+
continue;
|
|
4561
|
+
}
|
|
4083
4562
|
try {
|
|
4084
4563
|
const waveformDataPromise = clipDesc.peaksSrc ? this._resolvePeaks(clipDesc.peaksSrc) : Promise.resolve(null);
|
|
4085
4564
|
const audioPromise = this._fetchAndDecode(clipDesc.src);
|
|
@@ -4291,7 +4770,11 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4291
4770
|
nextTracks.set(track.id, track);
|
|
4292
4771
|
}
|
|
4293
4772
|
this._engineTracks = nextTracks;
|
|
4294
|
-
|
|
4773
|
+
const audioTracks = engineState.tracks.filter((t) => {
|
|
4774
|
+
const desc = this._tracks.get(t.id);
|
|
4775
|
+
return desc?.renderMode !== "piano-roll";
|
|
4776
|
+
});
|
|
4777
|
+
syncPeaksForChangedClips(this, audioTracks);
|
|
4295
4778
|
}
|
|
4296
4779
|
});
|
|
4297
4780
|
engine.on("pause", () => {
|
|
@@ -4366,7 +4849,17 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4366
4849
|
if (config.pan !== void 0) trackEl.pan = config.pan;
|
|
4367
4850
|
if (config.muted) trackEl.setAttribute("muted", "");
|
|
4368
4851
|
if (config.soloed) trackEl.setAttribute("soloed", "");
|
|
4369
|
-
|
|
4852
|
+
const renderMode = config.renderMode ?? (config.midi ? "piano-roll" : void 0);
|
|
4853
|
+
if (renderMode !== void 0) trackEl.setAttribute("render-mode", renderMode);
|
|
4854
|
+
const clipConfigs = [...config.clips ?? []];
|
|
4855
|
+
if (config.midi) {
|
|
4856
|
+
clipConfigs.push({
|
|
4857
|
+
midiNotes: config.midi.notes,
|
|
4858
|
+
midiChannel: config.midi.channel,
|
|
4859
|
+
midiProgram: config.midi.program
|
|
4860
|
+
});
|
|
4861
|
+
}
|
|
4862
|
+
for (const clipConfig of clipConfigs) {
|
|
4370
4863
|
trackEl.appendChild(this._buildClipElement(clipConfig));
|
|
4371
4864
|
}
|
|
4372
4865
|
return this._awaitId(
|
|
@@ -4412,6 +4905,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4412
4905
|
if (partial.soloed) trackEl.setAttribute("soloed", "");
|
|
4413
4906
|
else trackEl.removeAttribute("soloed");
|
|
4414
4907
|
}
|
|
4908
|
+
if (partial.renderMode !== void 0) trackEl.setAttribute("render-mode", partial.renderMode);
|
|
4415
4909
|
return;
|
|
4416
4910
|
}
|
|
4417
4911
|
const oldDesc = this._tracks.get(trackId);
|
|
@@ -4422,7 +4916,8 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4422
4916
|
...partial.volume !== void 0 && { volume: partial.volume },
|
|
4423
4917
|
...partial.pan !== void 0 && { pan: partial.pan },
|
|
4424
4918
|
...partial.muted !== void 0 && { muted: partial.muted },
|
|
4425
|
-
...partial.soloed !== void 0 && { soloed: partial.soloed }
|
|
4919
|
+
...partial.soloed !== void 0 && { soloed: partial.soloed },
|
|
4920
|
+
...partial.renderMode !== void 0 && { renderMode: partial.renderMode }
|
|
4426
4921
|
};
|
|
4427
4922
|
this._tracks = new Map(this._tracks).set(trackId, newDesc);
|
|
4428
4923
|
if (this._engine) {
|
|
@@ -4557,6 +5052,11 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4557
5052
|
if (config.fadeIn !== void 0) clipEl.fadeIn = config.fadeIn;
|
|
4558
5053
|
if (config.fadeOut !== void 0) clipEl.fadeOut = config.fadeOut;
|
|
4559
5054
|
if (config.fadeType !== void 0) clipEl.setAttribute("fade-type", config.fadeType);
|
|
5055
|
+
if (config.midiNotes !== void 0) clipEl.midiNotes = config.midiNotes;
|
|
5056
|
+
if (config.midiChannel !== void 0)
|
|
5057
|
+
clipEl.setAttribute("midi-channel", String(config.midiChannel));
|
|
5058
|
+
if (config.midiProgram !== void 0)
|
|
5059
|
+
clipEl.setAttribute("midi-program", String(config.midiProgram));
|
|
4560
5060
|
return clipEl;
|
|
4561
5061
|
}
|
|
4562
5062
|
// --- Playback ---
|
|
@@ -4592,7 +5092,9 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4592
5092
|
}
|
|
4593
5093
|
/** Toggle between play and pause. */
|
|
4594
5094
|
togglePlayPause() {
|
|
4595
|
-
if (this.
|
|
5095
|
+
if (this.isRecording) {
|
|
5096
|
+
this.togglePauseRecording();
|
|
5097
|
+
} else if (this._isPlaying) {
|
|
4596
5098
|
this.pause();
|
|
4597
5099
|
} else {
|
|
4598
5100
|
this.play();
|
|
@@ -4666,14 +5168,41 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4666
5168
|
get isRecording() {
|
|
4667
5169
|
return this._recordingController.isRecording;
|
|
4668
5170
|
}
|
|
5171
|
+
get isRecordingPaused() {
|
|
5172
|
+
return this._recordingController.isPaused;
|
|
5173
|
+
}
|
|
4669
5174
|
pauseRecording() {
|
|
4670
5175
|
this._recordingController.pauseRecording();
|
|
4671
5176
|
}
|
|
4672
5177
|
resumeRecording() {
|
|
4673
5178
|
this._recordingController.resumeRecording();
|
|
5179
|
+
this._wasPlayingDuringRecording = false;
|
|
5180
|
+
}
|
|
5181
|
+
/**
|
|
5182
|
+
* Audacity-style pause toggle for active recordings: pauses both the
|
|
5183
|
+
* worklet capture and (if running) the playback Transport. On resume,
|
|
5184
|
+
* Transport restarts only if it was running before — non-overdub
|
|
5185
|
+
* recordings stay silent on resume.
|
|
5186
|
+
*/
|
|
5187
|
+
togglePauseRecording() {
|
|
5188
|
+
if (!this.isRecording) return;
|
|
5189
|
+
if (this.isRecordingPaused) {
|
|
5190
|
+
const wasPlaying = this._wasPlayingDuringRecording;
|
|
5191
|
+
this.resumeRecording();
|
|
5192
|
+
if (wasPlaying) {
|
|
5193
|
+
void this.play(this.currentTime);
|
|
5194
|
+
}
|
|
5195
|
+
} else {
|
|
5196
|
+
this.pauseRecording();
|
|
5197
|
+
if (this._isPlaying) {
|
|
5198
|
+
this._wasPlayingDuringRecording = true;
|
|
5199
|
+
this.pause();
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
4674
5202
|
}
|
|
4675
5203
|
stopRecording() {
|
|
4676
|
-
this.
|
|
5204
|
+
this._wasPlayingDuringRecording = false;
|
|
5205
|
+
return this._recordingController.stopRecording();
|
|
4677
5206
|
}
|
|
4678
5207
|
_addRecordedClip(trackId, buf, startSample, durSamples, offsetSamples = 0) {
|
|
4679
5208
|
addRecordedClip(this, trackId, buf, startSample, durSamples, offsetSamples);
|
|
@@ -4709,7 +5238,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4709
5238
|
const w = Math.floor(audibleSamples / renderSpp);
|
|
4710
5239
|
return rs.peaks.map((chPeaks, ch) => {
|
|
4711
5240
|
const slicedPeaks = latencyPixels > 0 ? chPeaks.slice(latencyPixels * 2) : chPeaks;
|
|
4712
|
-
return
|
|
5241
|
+
return import_lit14.html`
|
|
4713
5242
|
<daw-waveform
|
|
4714
5243
|
data-recording-track=${trackId}
|
|
4715
5244
|
data-recording-channel=${ch}
|
|
@@ -4806,11 +5335,11 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4806
5335
|
trackHeight: this.waveHeight * numChannels + (this.clipHeaders ? this.clipHeaderHeight : 0)
|
|
4807
5336
|
};
|
|
4808
5337
|
});
|
|
4809
|
-
return
|
|
4810
|
-
${orderedTracks.length > 0 || this.indefinitePlayback ?
|
|
4811
|
-
${this.timescale ?
|
|
5338
|
+
return import_lit14.html`
|
|
5339
|
+
${orderedTracks.length > 0 || this.indefinitePlayback ? import_lit14.html`<div class="controls-column">
|
|
5340
|
+
${this.timescale ? import_lit14.html`<div style="height: 30px;"></div>` : ""}
|
|
4812
5341
|
${orderedTracks.map(
|
|
4813
|
-
(t) =>
|
|
5342
|
+
(t) => import_lit14.html`
|
|
4814
5343
|
<daw-track-controls
|
|
4815
5344
|
style="height: ${t.trackHeight}px;"
|
|
4816
5345
|
.trackId=${t.trackId}
|
|
@@ -4833,7 +5362,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4833
5362
|
@dragleave=${this._onDragLeave}
|
|
4834
5363
|
@drop=${this._onDrop}
|
|
4835
5364
|
>
|
|
4836
|
-
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ?
|
|
5365
|
+
${(orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback) && this.timescale ? import_lit14.html`<daw-ruler
|
|
4837
5366
|
.samplesPerPixel=${spp}
|
|
4838
5367
|
.sampleRate=${this.effectiveSampleRate}
|
|
4839
5368
|
.duration=${this._duration}
|
|
@@ -4843,7 +5372,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4843
5372
|
.ppqn=${this.ppqn}
|
|
4844
5373
|
.totalWidth=${this._totalWidth}
|
|
4845
5374
|
></daw-ruler>` : ""}
|
|
4846
|
-
${this.scaleMode === "beats" ?
|
|
5375
|
+
${this.scaleMode === "beats" ? import_lit14.html`<daw-grid
|
|
4847
5376
|
style="top: ${this.timescale ? 30 : 0}px;"
|
|
4848
5377
|
.ticksPerPixel=${this.ticksPerPixel}
|
|
4849
5378
|
.meterEntries=${this._meterEntries}
|
|
@@ -4853,11 +5382,11 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4853
5382
|
.length=${this._totalWidth}
|
|
4854
5383
|
.height=${orderedTracks.length > 0 ? orderedTracks.reduce((sum, t) => sum + t.trackHeight + 1, 0) : this._emptyGridHeight}
|
|
4855
5384
|
></daw-grid>` : ""}
|
|
4856
|
-
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ?
|
|
5385
|
+
${orderedTracks.length > 0 || this.scaleMode === "beats" || this.indefinitePlayback ? import_lit14.html`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>
|
|
4857
5386
|
<daw-playhead></daw-playhead>` : ""}
|
|
4858
5387
|
${orderedTracks.map((t) => {
|
|
4859
5388
|
const channelHeight = this.waveHeight;
|
|
4860
|
-
return
|
|
5389
|
+
return import_lit14.html`
|
|
4861
5390
|
<div
|
|
4862
5391
|
class="track-row ${t.trackId === this._selectedTrackId ? "selected" : ""}"
|
|
4863
5392
|
style="height: ${t.trackHeight}px;"
|
|
@@ -4920,12 +5449,12 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4920
5449
|
const channels = segmentChannels ?? peakData?.data ?? [new Int16Array(0)];
|
|
4921
5450
|
const hdrH = this.clipHeaders ? this.clipHeaderHeight : 0;
|
|
4922
5451
|
const chH = this.waveHeight;
|
|
4923
|
-
return
|
|
5452
|
+
return import_lit14.html` <div
|
|
4924
5453
|
class="clip-container"
|
|
4925
5454
|
style="left:${clipLeft}px;top:0;width:${width}px;height:${t.trackHeight}px;"
|
|
4926
5455
|
data-clip-id=${clip.id}
|
|
4927
5456
|
>
|
|
4928
|
-
${hdrH > 0 ?
|
|
5457
|
+
${hdrH > 0 ? import_lit14.html`<div
|
|
4929
5458
|
class="clip-header"
|
|
4930
5459
|
data-clip-id=${clip.id}
|
|
4931
5460
|
data-track-id=${t.trackId}
|
|
@@ -4933,21 +5462,33 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4933
5462
|
>
|
|
4934
5463
|
<span>${clip.name || t.descriptor?.name || ""}</span>
|
|
4935
5464
|
</div>` : ""}
|
|
4936
|
-
${
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
.peaks=${chPeaks}
|
|
5465
|
+
${t.descriptor?.renderMode === "piano-roll" ? import_lit14.html`<daw-piano-roll
|
|
5466
|
+
style="position:absolute;left:0;top:${hdrH}px;"
|
|
5467
|
+
.midiNotes=${clip.midiNotes ?? []}
|
|
4940
5468
|
.length=${peakData?.length ?? width}
|
|
4941
|
-
.waveHeight=${chH}
|
|
4942
|
-
.
|
|
4943
|
-
.
|
|
5469
|
+
.waveHeight=${chH * channels.length}
|
|
5470
|
+
.samplesPerPixel=${this._renderSpp}
|
|
5471
|
+
.sampleRate=${this.effectiveSampleRate}
|
|
5472
|
+
.clipOffsetSeconds=${(clip.offsetSamples ?? 0) / this.effectiveSampleRate}
|
|
4944
5473
|
.visibleStart=${this._viewport.visibleStart}
|
|
4945
5474
|
.visibleEnd=${this._viewport.visibleEnd}
|
|
4946
5475
|
.originX=${clipLeft}
|
|
4947
|
-
|
|
4948
|
-
></daw-
|
|
5476
|
+
?selected=${t.trackId === this._selectedTrackId}
|
|
5477
|
+
></daw-piano-roll>` : channels.map(
|
|
5478
|
+
(chPeaks, chIdx) => import_lit14.html` <daw-waveform
|
|
5479
|
+
style="position:absolute;left:0;top:${hdrH + chIdx * chH}px;"
|
|
5480
|
+
.peaks=${chPeaks}
|
|
5481
|
+
.length=${peakData?.length ?? width}
|
|
5482
|
+
.waveHeight=${chH}
|
|
5483
|
+
.barWidth=${this.barWidth}
|
|
5484
|
+
.barGap=${this.barGap}
|
|
5485
|
+
.visibleStart=${this._viewport.visibleStart}
|
|
5486
|
+
.visibleEnd=${this._viewport.visibleEnd}
|
|
5487
|
+
.originX=${clipLeft}
|
|
5488
|
+
.segments=${clipSegments}
|
|
5489
|
+
></daw-waveform>`
|
|
4949
5490
|
)}
|
|
4950
|
-
${this.interactiveClips ?
|
|
5491
|
+
${this.interactiveClips ? import_lit14.html` <div
|
|
4951
5492
|
class="clip-boundary"
|
|
4952
5493
|
data-boundary-edge="left"
|
|
4953
5494
|
data-clip-id=${clip.id}
|
|
@@ -4973,7 +5514,7 @@ var DawEditorElement = class extends import_lit13.LitElement {
|
|
|
4973
5514
|
};
|
|
4974
5515
|
DawEditorElement.styles = [
|
|
4975
5516
|
hostStyles,
|
|
4976
|
-
|
|
5517
|
+
import_lit14.css`
|
|
4977
5518
|
:host {
|
|
4978
5519
|
display: flex;
|
|
4979
5520
|
position: relative;
|
|
@@ -5021,99 +5562,99 @@ DawEditorElement.styles = [
|
|
|
5021
5562
|
];
|
|
5022
5563
|
DawEditorElement._CONTROL_PROPS = /* @__PURE__ */ new Set(["volume", "pan", "muted", "soloed"]);
|
|
5023
5564
|
__decorateClass([
|
|
5024
|
-
(0,
|
|
5565
|
+
(0, import_decorators12.property)({ type: Number, attribute: "samples-per-pixel", noAccessor: true })
|
|
5025
5566
|
], DawEditorElement.prototype, "samplesPerPixel", 1);
|
|
5026
5567
|
__decorateClass([
|
|
5027
|
-
(0,
|
|
5568
|
+
(0, import_decorators12.property)({ type: Number, attribute: "wave-height" })
|
|
5028
5569
|
], DawEditorElement.prototype, "waveHeight", 2);
|
|
5029
5570
|
__decorateClass([
|
|
5030
|
-
(0,
|
|
5571
|
+
(0, import_decorators12.property)({ type: Boolean })
|
|
5031
5572
|
], DawEditorElement.prototype, "timescale", 2);
|
|
5032
5573
|
__decorateClass([
|
|
5033
|
-
(0,
|
|
5574
|
+
(0, import_decorators12.property)({ type: Boolean })
|
|
5034
5575
|
], DawEditorElement.prototype, "mono", 2);
|
|
5035
5576
|
__decorateClass([
|
|
5036
|
-
(0,
|
|
5577
|
+
(0, import_decorators12.property)({ type: Number, attribute: "bar-width" })
|
|
5037
5578
|
], DawEditorElement.prototype, "barWidth", 2);
|
|
5038
5579
|
__decorateClass([
|
|
5039
|
-
(0,
|
|
5580
|
+
(0, import_decorators12.property)({ type: Number, attribute: "bar-gap" })
|
|
5040
5581
|
], DawEditorElement.prototype, "barGap", 2);
|
|
5041
5582
|
__decorateClass([
|
|
5042
|
-
(0,
|
|
5583
|
+
(0, import_decorators12.property)({ type: Boolean, attribute: "file-drop" })
|
|
5043
5584
|
], DawEditorElement.prototype, "fileDrop", 2);
|
|
5044
5585
|
__decorateClass([
|
|
5045
|
-
(0,
|
|
5586
|
+
(0, import_decorators12.property)({ type: Boolean, attribute: "clip-headers" })
|
|
5046
5587
|
], DawEditorElement.prototype, "clipHeaders", 2);
|
|
5047
5588
|
__decorateClass([
|
|
5048
|
-
(0,
|
|
5589
|
+
(0, import_decorators12.property)({ type: Number, attribute: "clip-header-height" })
|
|
5049
5590
|
], DawEditorElement.prototype, "clipHeaderHeight", 2);
|
|
5050
5591
|
__decorateClass([
|
|
5051
|
-
(0,
|
|
5592
|
+
(0, import_decorators12.property)({ type: Boolean, attribute: "interactive-clips" })
|
|
5052
5593
|
], DawEditorElement.prototype, "interactiveClips", 2);
|
|
5053
5594
|
__decorateClass([
|
|
5054
|
-
(0,
|
|
5595
|
+
(0, import_decorators12.property)({ type: Boolean, attribute: "indefinite-playback" })
|
|
5055
5596
|
], DawEditorElement.prototype, "indefinitePlayback", 2);
|
|
5056
5597
|
__decorateClass([
|
|
5057
|
-
(0,
|
|
5598
|
+
(0, import_decorators12.property)({ type: String, attribute: "scale-mode" })
|
|
5058
5599
|
], DawEditorElement.prototype, "scaleMode", 2);
|
|
5059
5600
|
__decorateClass([
|
|
5060
|
-
(0,
|
|
5601
|
+
(0, import_decorators12.property)({ type: Number, attribute: "ticks-per-pixel", noAccessor: true })
|
|
5061
5602
|
], DawEditorElement.prototype, "ticksPerPixel", 1);
|
|
5062
5603
|
__decorateClass([
|
|
5063
|
-
(0,
|
|
5604
|
+
(0, import_decorators12.property)({ type: Number, noAccessor: true })
|
|
5064
5605
|
], DawEditorElement.prototype, "bpm", 1);
|
|
5065
5606
|
__decorateClass([
|
|
5066
|
-
(0,
|
|
5607
|
+
(0, import_decorators12.property)({ attribute: false })
|
|
5067
5608
|
], DawEditorElement.prototype, "timeSignature", 2);
|
|
5068
5609
|
__decorateClass([
|
|
5069
|
-
(0,
|
|
5610
|
+
(0, import_decorators12.property)({ attribute: false })
|
|
5070
5611
|
], DawEditorElement.prototype, "meterEntries", 2);
|
|
5071
5612
|
__decorateClass([
|
|
5072
|
-
(0,
|
|
5613
|
+
(0, import_decorators12.property)({ type: Number, noAccessor: true })
|
|
5073
5614
|
], DawEditorElement.prototype, "ppqn", 1);
|
|
5074
5615
|
__decorateClass([
|
|
5075
|
-
(0,
|
|
5616
|
+
(0, import_decorators12.property)({ type: String, attribute: "snap-to" })
|
|
5076
5617
|
], DawEditorElement.prototype, "snapTo", 2);
|
|
5077
5618
|
__decorateClass([
|
|
5078
|
-
(0,
|
|
5619
|
+
(0, import_decorators12.property)({ attribute: false })
|
|
5079
5620
|
], DawEditorElement.prototype, "secondsToTicks", 2);
|
|
5080
5621
|
__decorateClass([
|
|
5081
|
-
(0,
|
|
5622
|
+
(0, import_decorators12.property)({ attribute: false })
|
|
5082
5623
|
], DawEditorElement.prototype, "ticksToSeconds", 2);
|
|
5083
5624
|
__decorateClass([
|
|
5084
|
-
(0,
|
|
5625
|
+
(0, import_decorators12.state)()
|
|
5085
5626
|
], DawEditorElement.prototype, "_tracks", 2);
|
|
5086
5627
|
__decorateClass([
|
|
5087
|
-
(0,
|
|
5628
|
+
(0, import_decorators12.state)()
|
|
5088
5629
|
], DawEditorElement.prototype, "_engineTracks", 2);
|
|
5089
5630
|
__decorateClass([
|
|
5090
|
-
(0,
|
|
5631
|
+
(0, import_decorators12.state)()
|
|
5091
5632
|
], DawEditorElement.prototype, "_peaksData", 2);
|
|
5092
5633
|
__decorateClass([
|
|
5093
|
-
(0,
|
|
5634
|
+
(0, import_decorators12.state)()
|
|
5094
5635
|
], DawEditorElement.prototype, "_isPlaying", 2);
|
|
5095
5636
|
__decorateClass([
|
|
5096
|
-
(0,
|
|
5637
|
+
(0, import_decorators12.state)()
|
|
5097
5638
|
], DawEditorElement.prototype, "_duration", 2);
|
|
5098
5639
|
__decorateClass([
|
|
5099
|
-
(0,
|
|
5640
|
+
(0, import_decorators12.state)()
|
|
5100
5641
|
], DawEditorElement.prototype, "_selectedTrackId", 2);
|
|
5101
5642
|
__decorateClass([
|
|
5102
|
-
(0,
|
|
5643
|
+
(0, import_decorators12.state)()
|
|
5103
5644
|
], DawEditorElement.prototype, "_dragOver", 2);
|
|
5104
5645
|
__decorateClass([
|
|
5105
|
-
(0,
|
|
5646
|
+
(0, import_decorators12.property)({ attribute: false })
|
|
5106
5647
|
], DawEditorElement.prototype, "adapter", 1);
|
|
5107
5648
|
__decorateClass([
|
|
5108
|
-
(0,
|
|
5649
|
+
(0, import_decorators12.property)({ attribute: "eager-resume" })
|
|
5109
5650
|
], DawEditorElement.prototype, "eagerResume", 2);
|
|
5110
5651
|
DawEditorElement = __decorateClass([
|
|
5111
|
-
(0,
|
|
5652
|
+
(0, import_decorators12.customElement)("daw-editor")
|
|
5112
5653
|
], DawEditorElement);
|
|
5113
5654
|
|
|
5114
5655
|
// src/elements/daw-ruler.ts
|
|
5115
|
-
var
|
|
5116
|
-
var
|
|
5656
|
+
var import_lit15 = require("lit");
|
|
5657
|
+
var import_decorators13 = require("lit/decorators.js");
|
|
5117
5658
|
|
|
5118
5659
|
// src/utils/time-format.ts
|
|
5119
5660
|
function formatTime(milliseconds) {
|
|
@@ -5164,8 +5705,8 @@ function computeTemporalTicks(samplesPerPixel, sampleRate, duration, rulerHeight
|
|
|
5164
5705
|
}
|
|
5165
5706
|
|
|
5166
5707
|
// src/elements/daw-ruler.ts
|
|
5167
|
-
var
|
|
5168
|
-
var DawRulerElement = class extends
|
|
5708
|
+
var MAX_CANVAS_WIDTH4 = 1e3;
|
|
5709
|
+
var DawRulerElement = class extends import_lit15.LitElement {
|
|
5169
5710
|
constructor() {
|
|
5170
5711
|
super(...arguments);
|
|
5171
5712
|
this.samplesPerPixel = 1024;
|
|
@@ -5209,33 +5750,33 @@ var DawRulerElement = class extends import_lit14.LitElement {
|
|
|
5209
5750
|
}
|
|
5210
5751
|
render() {
|
|
5211
5752
|
const widthX = this.scaleMode === "beats" ? this.totalWidth : this._tickData?.widthX ?? 0;
|
|
5212
|
-
if (widthX <= 0) return
|
|
5213
|
-
const totalChunks = Math.ceil(widthX /
|
|
5753
|
+
if (widthX <= 0) return import_lit15.html``;
|
|
5754
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH4);
|
|
5214
5755
|
const indices = Array.from({ length: totalChunks }, (_, i) => i);
|
|
5215
5756
|
const dpr = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
|
5216
5757
|
const beatsLabels = this.scaleMode === "beats" ? this._musicalTickData?.ticks.filter((t) => t.label) ?? [] : [];
|
|
5217
5758
|
const temporalLabels = this.scaleMode !== "beats" ? this._tickData?.labels ?? [] : [];
|
|
5218
|
-
return
|
|
5759
|
+
return import_lit15.html`
|
|
5219
5760
|
<div class="container" style="width: ${widthX}px; height: ${this.rulerHeight}px;">
|
|
5220
5761
|
${indices.map((i) => {
|
|
5221
|
-
const width = Math.min(
|
|
5222
|
-
return
|
|
5762
|
+
const width = Math.min(MAX_CANVAS_WIDTH4, widthX - i * MAX_CANVAS_WIDTH4);
|
|
5763
|
+
return import_lit15.html`
|
|
5223
5764
|
<canvas
|
|
5224
5765
|
data-index=${i}
|
|
5225
5766
|
width=${width * dpr}
|
|
5226
5767
|
height=${this.rulerHeight * dpr}
|
|
5227
|
-
style="left: ${i *
|
|
5768
|
+
style="left: ${i * MAX_CANVAS_WIDTH4}px; width: ${width}px; height: ${this.rulerHeight}px;"
|
|
5228
5769
|
></canvas>
|
|
5229
5770
|
`;
|
|
5230
5771
|
})}
|
|
5231
5772
|
${this.scaleMode === "beats" ? beatsLabels.map(
|
|
5232
|
-
(t) =>
|
|
5773
|
+
(t) => import_lit15.html`<span
|
|
5233
5774
|
class="label ${t.pixel > 0 ? "centered" : ""}"
|
|
5234
5775
|
style="left: ${t.pixel > 0 ? t.pixel : t.pixel + 4}px;"
|
|
5235
5776
|
>${t.label}</span
|
|
5236
5777
|
>`
|
|
5237
5778
|
) : temporalLabels.map(
|
|
5238
|
-
({ pix, text }) =>
|
|
5779
|
+
({ pix, text }) => import_lit15.html`<span class="label" style="left: ${pix + 4}px;">${text}</span>`
|
|
5239
5780
|
)}
|
|
5240
5781
|
</div>
|
|
5241
5782
|
`;
|
|
@@ -5253,8 +5794,8 @@ var DawRulerElement = class extends import_lit14.LitElement {
|
|
|
5253
5794
|
const idx = Number(canvas.dataset.index);
|
|
5254
5795
|
const ctx = canvas.getContext("2d");
|
|
5255
5796
|
if (!ctx) continue;
|
|
5256
|
-
const canvasWidth = Math.min(
|
|
5257
|
-
const globalOffset = idx *
|
|
5797
|
+
const canvasWidth = Math.min(MAX_CANVAS_WIDTH4, widthX - idx * MAX_CANVAS_WIDTH4);
|
|
5798
|
+
const globalOffset = idx * MAX_CANVAS_WIDTH4;
|
|
5258
5799
|
ctx.resetTransform();
|
|
5259
5800
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
5260
5801
|
ctx.scale(dpr, dpr);
|
|
@@ -5286,7 +5827,7 @@ var DawRulerElement = class extends import_lit14.LitElement {
|
|
|
5286
5827
|
}
|
|
5287
5828
|
}
|
|
5288
5829
|
};
|
|
5289
|
-
DawRulerElement.styles =
|
|
5830
|
+
DawRulerElement.styles = import_lit15.css`
|
|
5290
5831
|
:host {
|
|
5291
5832
|
display: block;
|
|
5292
5833
|
position: relative;
|
|
@@ -5312,40 +5853,40 @@ DawRulerElement.styles = import_lit14.css`
|
|
|
5312
5853
|
}
|
|
5313
5854
|
`;
|
|
5314
5855
|
__decorateClass([
|
|
5315
|
-
(0,
|
|
5856
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5316
5857
|
], DawRulerElement.prototype, "samplesPerPixel", 2);
|
|
5317
5858
|
__decorateClass([
|
|
5318
|
-
(0,
|
|
5859
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5319
5860
|
], DawRulerElement.prototype, "sampleRate", 2);
|
|
5320
5861
|
__decorateClass([
|
|
5321
|
-
(0,
|
|
5862
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5322
5863
|
], DawRulerElement.prototype, "duration", 2);
|
|
5323
5864
|
__decorateClass([
|
|
5324
|
-
(0,
|
|
5865
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5325
5866
|
], DawRulerElement.prototype, "rulerHeight", 2);
|
|
5326
5867
|
__decorateClass([
|
|
5327
|
-
(0,
|
|
5868
|
+
(0, import_decorators13.property)({ type: String, attribute: false })
|
|
5328
5869
|
], DawRulerElement.prototype, "scaleMode", 2);
|
|
5329
5870
|
__decorateClass([
|
|
5330
|
-
(0,
|
|
5871
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5331
5872
|
], DawRulerElement.prototype, "ticksPerPixel", 2);
|
|
5332
5873
|
__decorateClass([
|
|
5333
|
-
(0,
|
|
5874
|
+
(0, import_decorators13.property)({ attribute: false })
|
|
5334
5875
|
], DawRulerElement.prototype, "meterEntries", 2);
|
|
5335
5876
|
__decorateClass([
|
|
5336
|
-
(0,
|
|
5877
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5337
5878
|
], DawRulerElement.prototype, "ppqn", 2);
|
|
5338
5879
|
__decorateClass([
|
|
5339
|
-
(0,
|
|
5880
|
+
(0, import_decorators13.property)({ type: Number, attribute: false })
|
|
5340
5881
|
], DawRulerElement.prototype, "totalWidth", 2);
|
|
5341
5882
|
DawRulerElement = __decorateClass([
|
|
5342
|
-
(0,
|
|
5883
|
+
(0, import_decorators13.customElement)("daw-ruler")
|
|
5343
5884
|
], DawRulerElement);
|
|
5344
5885
|
|
|
5345
5886
|
// src/elements/daw-selection.ts
|
|
5346
|
-
var
|
|
5347
|
-
var
|
|
5348
|
-
var DawSelectionElement = class extends
|
|
5887
|
+
var import_lit16 = require("lit");
|
|
5888
|
+
var import_decorators14 = require("lit/decorators.js");
|
|
5889
|
+
var DawSelectionElement = class extends import_lit16.LitElement {
|
|
5349
5890
|
constructor() {
|
|
5350
5891
|
super(...arguments);
|
|
5351
5892
|
this.startPx = 0;
|
|
@@ -5354,11 +5895,11 @@ var DawSelectionElement = class extends import_lit15.LitElement {
|
|
|
5354
5895
|
render() {
|
|
5355
5896
|
const left = Math.min(this.startPx, this.endPx);
|
|
5356
5897
|
const width = Math.abs(this.endPx - this.startPx);
|
|
5357
|
-
if (width === 0) return
|
|
5358
|
-
return
|
|
5898
|
+
if (width === 0) return import_lit16.html``;
|
|
5899
|
+
return import_lit16.html`<div style="left: ${left}px; width: ${width}px;"></div>`;
|
|
5359
5900
|
}
|
|
5360
5901
|
};
|
|
5361
|
-
DawSelectionElement.styles =
|
|
5902
|
+
DawSelectionElement.styles = import_lit16.css`
|
|
5362
5903
|
:host {
|
|
5363
5904
|
position: absolute;
|
|
5364
5905
|
top: 0;
|
|
@@ -5375,18 +5916,18 @@ DawSelectionElement.styles = import_lit15.css`
|
|
|
5375
5916
|
}
|
|
5376
5917
|
`;
|
|
5377
5918
|
__decorateClass([
|
|
5378
|
-
(0,
|
|
5919
|
+
(0, import_decorators14.property)({ type: Number, attribute: false })
|
|
5379
5920
|
], DawSelectionElement.prototype, "startPx", 2);
|
|
5380
5921
|
__decorateClass([
|
|
5381
|
-
(0,
|
|
5922
|
+
(0, import_decorators14.property)({ type: Number, attribute: false })
|
|
5382
5923
|
], DawSelectionElement.prototype, "endPx", 2);
|
|
5383
5924
|
DawSelectionElement = __decorateClass([
|
|
5384
|
-
(0,
|
|
5925
|
+
(0, import_decorators14.customElement)("daw-selection")
|
|
5385
5926
|
], DawSelectionElement);
|
|
5386
5927
|
|
|
5387
5928
|
// src/elements/daw-record-button.ts
|
|
5388
|
-
var
|
|
5389
|
-
var
|
|
5929
|
+
var import_lit17 = require("lit");
|
|
5930
|
+
var import_decorators15 = require("lit/decorators.js");
|
|
5390
5931
|
var DawRecordButtonElement = class extends DawTransportButton {
|
|
5391
5932
|
constructor() {
|
|
5392
5933
|
super(...arguments);
|
|
@@ -5427,7 +5968,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
5427
5968
|
}
|
|
5428
5969
|
}
|
|
5429
5970
|
render() {
|
|
5430
|
-
return
|
|
5971
|
+
return import_lit17.html`
|
|
5431
5972
|
<button part="button" ?data-recording=${this._isRecording} @click=${this._onClick}>
|
|
5432
5973
|
<slot>Record</slot>
|
|
5433
5974
|
</button>
|
|
@@ -5447,7 +5988,7 @@ var DawRecordButtonElement = class extends DawTransportButton {
|
|
|
5447
5988
|
};
|
|
5448
5989
|
DawRecordButtonElement.styles = [
|
|
5449
5990
|
DawTransportButton.styles,
|
|
5450
|
-
|
|
5991
|
+
import_lit17.css`
|
|
5451
5992
|
button[data-recording] {
|
|
5452
5993
|
color: #d08070;
|
|
5453
5994
|
border-color: #d08070;
|
|
@@ -5456,17 +5997,17 @@ DawRecordButtonElement.styles = [
|
|
|
5456
5997
|
`
|
|
5457
5998
|
];
|
|
5458
5999
|
__decorateClass([
|
|
5459
|
-
(0,
|
|
6000
|
+
(0, import_decorators15.state)()
|
|
5460
6001
|
], DawRecordButtonElement.prototype, "_isRecording", 2);
|
|
5461
6002
|
DawRecordButtonElement = __decorateClass([
|
|
5462
|
-
(0,
|
|
6003
|
+
(0, import_decorators15.customElement)("daw-record-button")
|
|
5463
6004
|
], DawRecordButtonElement);
|
|
5464
6005
|
|
|
5465
6006
|
// src/elements/daw-keyboard-shortcuts.ts
|
|
5466
|
-
var
|
|
5467
|
-
var
|
|
6007
|
+
var import_lit18 = require("lit");
|
|
6008
|
+
var import_decorators16 = require("lit/decorators.js");
|
|
5468
6009
|
var import_core9 = require("@waveform-playlist/core");
|
|
5469
|
-
var DawKeyboardShortcutsElement = class extends
|
|
6010
|
+
var DawKeyboardShortcutsElement = class extends import_lit18.LitElement {
|
|
5470
6011
|
constructor() {
|
|
5471
6012
|
super(...arguments);
|
|
5472
6013
|
this.playback = false;
|
|
@@ -5620,16 +6161,16 @@ var DawKeyboardShortcutsElement = class extends import_lit17.LitElement {
|
|
|
5620
6161
|
}
|
|
5621
6162
|
};
|
|
5622
6163
|
__decorateClass([
|
|
5623
|
-
(0,
|
|
6164
|
+
(0, import_decorators16.property)({ type: Boolean })
|
|
5624
6165
|
], DawKeyboardShortcutsElement.prototype, "playback", 2);
|
|
5625
6166
|
__decorateClass([
|
|
5626
|
-
(0,
|
|
6167
|
+
(0, import_decorators16.property)({ type: Boolean })
|
|
5627
6168
|
], DawKeyboardShortcutsElement.prototype, "splitting", 2);
|
|
5628
6169
|
__decorateClass([
|
|
5629
|
-
(0,
|
|
6170
|
+
(0, import_decorators16.property)({ type: Boolean })
|
|
5630
6171
|
], DawKeyboardShortcutsElement.prototype, "undo", 2);
|
|
5631
6172
|
DawKeyboardShortcutsElement = __decorateClass([
|
|
5632
|
-
(0,
|
|
6173
|
+
(0, import_decorators16.customElement)("daw-keyboard-shortcuts")
|
|
5633
6174
|
], DawKeyboardShortcutsElement);
|
|
5634
6175
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5635
6176
|
0 && (module.exports = {
|
|
@@ -5640,6 +6181,7 @@ DawKeyboardShortcutsElement = __decorateClass([
|
|
|
5640
6181
|
DawGridElement,
|
|
5641
6182
|
DawKeyboardShortcutsElement,
|
|
5642
6183
|
DawPauseButtonElement,
|
|
6184
|
+
DawPianoRollElement,
|
|
5643
6185
|
DawPlayButtonElement,
|
|
5644
6186
|
DawPlayheadElement,
|
|
5645
6187
|
DawRecordButtonElement,
|