solid-pianoroll 0.0.10 → 0.0.12
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/cjs/index.js +340 -140
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +341 -143
- package/dist/esm/index.js.map +1 -1
- package/dist/source/MultiTrackPianoRoll.jsx +136 -0
- package/dist/source/PianoRoll.jsx +3 -20
- package/dist/source/PianoRollContext.jsx +20 -1
- package/dist/source/PianoRollNotes.jsx +14 -7
- package/dist/source/index.jsx +3 -1
- package/dist/source/useNotes.js +23 -0
- package/dist/source/usePianoRoll.js +4 -24
- package/dist/source/viewport/HorizontalZoomControl.jsx +1 -0
- package/dist/source/viewport/createViewPortDimension.js +4 -0
- package/dist/types/MultiTrackPianoRoll.d.ts +10 -0
- package/dist/types/PianoRollContext.d.ts +1 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/useNotes.d.ts +9 -0
- package/dist/types/usePianoRoll.d.ts +2 -6
- package/dist/types/viewport/ScrollZoomViewPort.d.ts +4 -0
- package/dist/types/viewport/createViewPortDimension.d.ts +4 -0
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createContext, useContext, createEffect, createMemo, Index, Show,
|
|
1
|
+
import { spread, mergeProps, template, createComponent, delegateEvents, use, insert, memo, effect, className, style, classList, setAttribute } from 'solid-js/web';
|
|
2
|
+
import { createContext, splitProps, useContext, createEffect, createMemo, createSignal, Index, Show, mergeProps as mergeProps$1 } from 'solid-js';
|
|
3
3
|
import { createStore } from 'solid-js/store';
|
|
4
4
|
|
|
5
5
|
function styleInject(css, ref) {
|
|
@@ -27,7 +27,7 @@ function styleInject(css, ref) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n
|
|
30
|
+
var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
|
|
31
31
|
var styles$3 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
|
|
32
32
|
styleInject(css_248z$3);
|
|
33
33
|
|
|
@@ -38,10 +38,30 @@ const usePianoRollContext = () => {
|
|
|
38
38
|
if (!context) throw new Error("No PianoRollContext found");
|
|
39
39
|
return context;
|
|
40
40
|
};
|
|
41
|
+
const splitContextProps = allProps => splitProps(allProps, ["condensed", "duration", "gridDivision", "notes", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange"]);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const _tmpl$$7 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
|
|
44
|
+
const HorizontalZoomControl = props => {
|
|
45
|
+
const context = usePianoRollContext();
|
|
46
|
+
return (() => {
|
|
47
|
+
const _el$ = _tmpl$$7.cloneNode(true);
|
|
48
|
+
spread(_el$, mergeProps(props, {
|
|
49
|
+
get value() {
|
|
50
|
+
return context.zoom;
|
|
51
|
+
},
|
|
52
|
+
"onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
|
|
53
|
+
"type": "range",
|
|
54
|
+
get style() {
|
|
55
|
+
return {
|
|
56
|
+
"margin-left": "50px",
|
|
57
|
+
"margin-right": "16px",
|
|
58
|
+
...(typeof props.style === "object" && props.style)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}), false, false);
|
|
62
|
+
return _el$;
|
|
63
|
+
})();
|
|
64
|
+
};
|
|
45
65
|
|
|
46
66
|
function createViewPortDimension(getState) {
|
|
47
67
|
const getStateWithFunctions = () => ({
|
|
@@ -50,7 +70,8 @@ function createViewPortDimension(getState) {
|
|
|
50
70
|
calculatePosition,
|
|
51
71
|
calculatePixelDimensions,
|
|
52
72
|
calculateVisibleRange,
|
|
53
|
-
calculateMaxPosition
|
|
73
|
+
calculateMaxPosition,
|
|
74
|
+
isVisible
|
|
54
75
|
});
|
|
55
76
|
const [state, setState] = createStore(getStateWithFunctions());
|
|
56
77
|
createEffect(() => setState(getStateWithFunctions()));
|
|
@@ -80,6 +101,12 @@ function createViewPortDimension(getState) {
|
|
|
80
101
|
size
|
|
81
102
|
};
|
|
82
103
|
}
|
|
104
|
+
function isVisible({
|
|
105
|
+
offset,
|
|
106
|
+
size
|
|
107
|
+
}) {
|
|
108
|
+
return offset + size > 0 && offset < state.pixelSize;
|
|
109
|
+
}
|
|
83
110
|
return state;
|
|
84
111
|
}
|
|
85
112
|
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
@@ -107,70 +134,11 @@ const useViewPortDimension = name => {
|
|
|
107
134
|
return viewPort;
|
|
108
135
|
};
|
|
109
136
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return (() => {
|
|
114
|
-
const _el$ = _tmpl$$6.cloneNode(true);
|
|
115
|
-
insert(_el$, createComponent(Index, {
|
|
116
|
-
each: keys,
|
|
117
|
-
children: key => {
|
|
118
|
-
const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
|
|
119
|
-
return createComponent(Show, {
|
|
120
|
-
get when() {
|
|
121
|
-
return virtualDimensions().size > 0;
|
|
122
|
-
},
|
|
123
|
-
get children() {
|
|
124
|
-
const _el$2 = _tmpl$$6.cloneNode(true);
|
|
125
|
-
effect(_p$ => {
|
|
126
|
-
const _v$ = {
|
|
127
|
-
[styles$2["Key"]]: true,
|
|
128
|
-
[styles$2["black"]]: key().isBlack,
|
|
129
|
-
[styles$2["white"]]: !key().isBlack,
|
|
130
|
-
[styles$2["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
|
|
131
|
-
[styles$2["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
|
|
132
|
-
},
|
|
133
|
-
_v$2 = key().name,
|
|
134
|
-
_v$3 = key().number % 12,
|
|
135
|
-
_v$4 = `${virtualDimensions().offset}px`,
|
|
136
|
-
_v$5 = `${virtualDimensions().size}px`;
|
|
137
|
-
_p$._v$ = classList(_el$2, _v$, _p$._v$);
|
|
138
|
-
_v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
|
|
139
|
-
_v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
|
|
140
|
-
_v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
|
|
141
|
-
_v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
|
|
142
|
-
return _p$;
|
|
143
|
-
}, {
|
|
144
|
-
_v$: undefined,
|
|
145
|
-
_v$2: undefined,
|
|
146
|
-
_v$3: undefined,
|
|
147
|
-
_v$4: undefined,
|
|
148
|
-
_v$5: undefined
|
|
149
|
-
});
|
|
150
|
-
return _el$2;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}));
|
|
155
|
-
effect(() => className(_el$, styles$2.PianoRollKeys));
|
|
156
|
-
return _el$;
|
|
157
|
-
})();
|
|
158
|
-
};
|
|
159
|
-
const blackKeys = [1, 3, 6, 8, 10];
|
|
160
|
-
const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
161
|
-
const keys = Array.from({
|
|
162
|
-
length: 128
|
|
163
|
-
}).map((_, index) => ({
|
|
164
|
-
number: index,
|
|
165
|
-
name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
|
|
166
|
-
isBlack: blackKeys.includes(index % 12)
|
|
167
|
-
}));
|
|
168
|
-
|
|
169
|
-
var css_248z$1 = ".PianoRollNotes-module_PianoRollNotes__6pF-y {\n position: absolute;\n flex: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb {\n position: absolute;\n box-sizing: border-box;\n border-width: 0.5px;\n border-style: solid;\n border-color: #a00;\n cursor: pointer;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimStart__vuBlj {\n cursor: w-resize;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimEnd__zPdjr {\n cursor: e-resize;\n}";
|
|
170
|
-
var styles$1 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
|
|
171
|
-
styleInject(css_248z$1);
|
|
137
|
+
var css_248z$2 = ".PianoRollNotes-module_PianoRollNotes__6pF-y {\n position: absolute;\n flex: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 1;\n cursor: grab;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb {\n position: absolute;\n box-sizing: border-box;\n border-width: 0.5px;\n border-style: solid;\n border-color: #a00;\n cursor: move;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimStart__vuBlj {\n cursor: w-resize;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimEnd__zPdjr {\n cursor: e-resize;\n}";
|
|
138
|
+
var styles$2 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
|
|
139
|
+
styleInject(css_248z$2);
|
|
172
140
|
|
|
173
|
-
const _tmpl$$
|
|
141
|
+
const _tmpl$$6 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
174
142
|
const PianoRollNotes = props => {
|
|
175
143
|
const context = usePianoRollContext();
|
|
176
144
|
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
@@ -179,7 +147,7 @@ const PianoRollNotes = props => {
|
|
|
179
147
|
const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
|
|
180
148
|
const insertOrUpdateNote = event => {
|
|
181
149
|
const position = horizontalViewPort().calculatePosition(event.clientX);
|
|
182
|
-
const midi = 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
|
|
150
|
+
const midi = context.condensed ? 60 : 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
|
|
183
151
|
const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
|
|
184
152
|
const velocity = 127;
|
|
185
153
|
const existingNote = newNote();
|
|
@@ -204,10 +172,10 @@ const PianoRollNotes = props => {
|
|
|
204
172
|
const [isMouseDown, setIsMouseDown] = createSignal(false);
|
|
205
173
|
const newNote = createMemo(() => context.notes[newNoteIndex()]);
|
|
206
174
|
const getClasses = noteDragMode => {
|
|
207
|
-
return noteDragMode ? [styles$
|
|
175
|
+
return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
|
|
208
176
|
};
|
|
209
177
|
return (() => {
|
|
210
|
-
const _el$ = _tmpl$$
|
|
178
|
+
const _el$ = _tmpl$$6.cloneNode(true);
|
|
211
179
|
_el$.$$click = event => {
|
|
212
180
|
if (newNote()) {
|
|
213
181
|
setNewNoteIndex(-1);
|
|
@@ -231,9 +199,6 @@ const PianoRollNotes = props => {
|
|
|
231
199
|
return;
|
|
232
200
|
}
|
|
233
201
|
const index = insertOrUpdateNote(event);
|
|
234
|
-
console.log({
|
|
235
|
-
index
|
|
236
|
-
});
|
|
237
202
|
setNewNoteIndex(index);
|
|
238
203
|
};
|
|
239
204
|
_el$.$$mousedown = () => {
|
|
@@ -247,14 +212,14 @@ const PianoRollNotes = props => {
|
|
|
247
212
|
return context.notes;
|
|
248
213
|
},
|
|
249
214
|
children: (note, index) => {
|
|
250
|
-
const
|
|
215
|
+
const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
|
|
251
216
|
const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
|
|
252
217
|
return createComponent(Show, {
|
|
253
218
|
get when() {
|
|
254
|
-
return memo(() =>
|
|
219
|
+
return memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
|
|
255
220
|
},
|
|
256
221
|
get children() {
|
|
257
|
-
const _el$2 = _tmpl$$
|
|
222
|
+
const _el$2 = _tmpl$$6.cloneNode(true);
|
|
258
223
|
_el$2.$$mousedown = event => {
|
|
259
224
|
event.stopPropagation();
|
|
260
225
|
setIsDragging(true);
|
|
@@ -264,7 +229,7 @@ const PianoRollNotes = props => {
|
|
|
264
229
|
const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
|
|
265
230
|
context.onNoteChange?.(index, {
|
|
266
231
|
...note(),
|
|
267
|
-
...(noteDragMode() === "move" && {
|
|
232
|
+
...(noteDragMode() === "move" && !context.condensed && {
|
|
268
233
|
midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
|
|
269
234
|
}),
|
|
270
235
|
...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
|
|
@@ -300,38 +265,37 @@ const PianoRollNotes = props => {
|
|
|
300
265
|
};
|
|
301
266
|
effect(_p$ => {
|
|
302
267
|
const _v$ = getClasses(noteDragMode()).join(" "),
|
|
303
|
-
_v$2 =
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
268
|
+
_v$2 = {
|
|
269
|
+
"background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
|
|
270
|
+
...(context.condensed ? {
|
|
271
|
+
top: 0,
|
|
272
|
+
height: "100%"
|
|
273
|
+
} : {
|
|
274
|
+
top: `${verticalVirtualDimensions().offset}px`,
|
|
275
|
+
height: `${verticalVirtualDimensions().size}px`
|
|
276
|
+
}),
|
|
277
|
+
left: `${horizontalDimensions().offset}px`,
|
|
278
|
+
width: `${horizontalDimensions().size}px`
|
|
279
|
+
};
|
|
308
280
|
_v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
|
|
309
|
-
|
|
310
|
-
_v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
|
|
311
|
-
_v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
|
|
312
|
-
_v$5 !== _p$._v$5 && _el$2.style.setProperty("left", _p$._v$5 = _v$5);
|
|
313
|
-
_v$6 !== _p$._v$6 && _el$2.style.setProperty("width", _p$._v$6 = _v$6);
|
|
281
|
+
_p$._v$2 = style(_el$2, _v$2, _p$._v$2);
|
|
314
282
|
return _p$;
|
|
315
283
|
}, {
|
|
316
284
|
_v$: undefined,
|
|
317
|
-
_v$2: undefined
|
|
318
|
-
_v$3: undefined,
|
|
319
|
-
_v$4: undefined,
|
|
320
|
-
_v$5: undefined,
|
|
321
|
-
_v$6: undefined
|
|
285
|
+
_v$2: undefined
|
|
322
286
|
});
|
|
323
287
|
return _el$2;
|
|
324
288
|
}
|
|
325
289
|
});
|
|
326
290
|
}
|
|
327
291
|
}));
|
|
328
|
-
effect(() => className(_el$, styles$
|
|
292
|
+
effect(() => className(_el$, styles$2.PianoRollNotes));
|
|
329
293
|
return _el$;
|
|
330
294
|
})();
|
|
331
295
|
};
|
|
332
296
|
delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
|
|
333
297
|
|
|
334
|
-
const _tmpl$$
|
|
298
|
+
const _tmpl$$5 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
|
|
335
299
|
const ScrollContainer = props => {
|
|
336
300
|
let scrollContentRef;
|
|
337
301
|
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
@@ -393,7 +357,7 @@ const ScrollContainer = props => {
|
|
|
393
357
|
});
|
|
394
358
|
});
|
|
395
359
|
return (() => {
|
|
396
|
-
const _el$ = _tmpl$$
|
|
360
|
+
const _el$ = _tmpl$$5.cloneNode(true),
|
|
397
361
|
_el$2 = _el$.firstChild,
|
|
398
362
|
_el$3 = _el$2.firstChild,
|
|
399
363
|
_el$4 = _el$3.firstChild;
|
|
@@ -434,6 +398,69 @@ const ScrollContainer = props => {
|
|
|
434
398
|
})();
|
|
435
399
|
};
|
|
436
400
|
|
|
401
|
+
var css_248z$1 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
|
|
402
|
+
var styles$1 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
|
|
403
|
+
styleInject(css_248z$1);
|
|
404
|
+
|
|
405
|
+
const _tmpl$$4 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
406
|
+
const PianoRollKeys = () => {
|
|
407
|
+
const viewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
408
|
+
return (() => {
|
|
409
|
+
const _el$ = _tmpl$$4.cloneNode(true);
|
|
410
|
+
insert(_el$, createComponent(Index, {
|
|
411
|
+
each: keys,
|
|
412
|
+
children: key => {
|
|
413
|
+
const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
|
|
414
|
+
return createComponent(Show, {
|
|
415
|
+
get when() {
|
|
416
|
+
return virtualDimensions().size > 0;
|
|
417
|
+
},
|
|
418
|
+
get children() {
|
|
419
|
+
const _el$2 = _tmpl$$4.cloneNode(true);
|
|
420
|
+
effect(_p$ => {
|
|
421
|
+
const _v$ = {
|
|
422
|
+
[styles$1["Key"]]: true,
|
|
423
|
+
[styles$1["black"]]: key().isBlack,
|
|
424
|
+
[styles$1["white"]]: !key().isBlack,
|
|
425
|
+
[styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
|
|
426
|
+
[styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
|
|
427
|
+
},
|
|
428
|
+
_v$2 = key().name,
|
|
429
|
+
_v$3 = key().number % 12,
|
|
430
|
+
_v$4 = `${virtualDimensions().offset}px`,
|
|
431
|
+
_v$5 = `${virtualDimensions().size}px`;
|
|
432
|
+
_p$._v$ = classList(_el$2, _v$, _p$._v$);
|
|
433
|
+
_v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
|
|
434
|
+
_v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
|
|
435
|
+
_v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
|
|
436
|
+
_v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
|
|
437
|
+
return _p$;
|
|
438
|
+
}, {
|
|
439
|
+
_v$: undefined,
|
|
440
|
+
_v$2: undefined,
|
|
441
|
+
_v$3: undefined,
|
|
442
|
+
_v$4: undefined,
|
|
443
|
+
_v$5: undefined
|
|
444
|
+
});
|
|
445
|
+
return _el$2;
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}));
|
|
450
|
+
effect(() => className(_el$, styles$1.PianoRollKeys));
|
|
451
|
+
return _el$;
|
|
452
|
+
})();
|
|
453
|
+
};
|
|
454
|
+
const blackKeys = [1, 3, 6, 8, 10];
|
|
455
|
+
const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
456
|
+
const keys = Array.from({
|
|
457
|
+
length: 128
|
|
458
|
+
}).map((_, index) => ({
|
|
459
|
+
number: index,
|
|
460
|
+
name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
|
|
461
|
+
isBlack: blackKeys.includes(index % 12)
|
|
462
|
+
}));
|
|
463
|
+
|
|
437
464
|
var css_248z = ".PianoRollGrid-module_PianoRollGrid__tG119 {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Key__VRbiB {\n position: absolute;\n border-style: solid;\n border-color: gray;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Time__jLz3E {\n position: absolute;\n box-sizing: border-box;\n top: 0px;\n height: 100%;\n border-left-style: solid;\n border-left-width: 0.5px;\n}\n";
|
|
438
465
|
var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
|
|
439
466
|
styleInject(css_248z);
|
|
@@ -550,6 +577,30 @@ const PianoRollGrid = () => {
|
|
|
550
577
|
})();
|
|
551
578
|
};
|
|
552
579
|
|
|
580
|
+
const useNotes = () => {
|
|
581
|
+
const [notes, onNotesChange] = createSignal([]);
|
|
582
|
+
const onNoteChange = (index, note) => {
|
|
583
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
584
|
+
};
|
|
585
|
+
const onInsertNote = note => {
|
|
586
|
+
const index = Math.max(notes().findIndex(({
|
|
587
|
+
ticks
|
|
588
|
+
}) => ticks > note.ticks), 0);
|
|
589
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
|
|
590
|
+
return index;
|
|
591
|
+
};
|
|
592
|
+
const onRemoveNote = index => {
|
|
593
|
+
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
594
|
+
};
|
|
595
|
+
return {
|
|
596
|
+
notes,
|
|
597
|
+
onNotesChange,
|
|
598
|
+
onNoteChange,
|
|
599
|
+
onInsertNote,
|
|
600
|
+
onRemoveNote
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
|
|
553
604
|
const defaultRect = {
|
|
554
605
|
left: 0,
|
|
555
606
|
width: 0,
|
|
@@ -606,29 +657,198 @@ const VerticalZoomControl = props => {
|
|
|
606
657
|
})();
|
|
607
658
|
};
|
|
608
659
|
|
|
609
|
-
const _tmpl$$1 = /*#__PURE__*/template(`<
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
660
|
+
const _tmpl$$1 = /*#__PURE__*/template(`<ul></ul>`, 2),
|
|
661
|
+
_tmpl$2 = /*#__PURE__*/template(`<div><ul></ul><div><div></div></div></div>`, 8),
|
|
662
|
+
_tmpl$3 = /*#__PURE__*/template(`<li></li>`, 2);
|
|
663
|
+
const MultiTrackPianoRoll = allProps => {
|
|
664
|
+
const condensed = createMemo(() => !allProps.selectedTrack);
|
|
665
|
+
const [ownProps, restProps] = splitProps(allProps, ["tracks", "selectedTrack"]);
|
|
666
|
+
const [contextProps, divProps] = splitContextProps(mergeProps$1(restProps, {
|
|
667
|
+
notes: [],
|
|
668
|
+
condensed: false
|
|
669
|
+
}));
|
|
670
|
+
const [scrollerRef, setScrollerRef] = createSignal();
|
|
671
|
+
const clientRect = useBoundingClientRect(scrollerRef);
|
|
672
|
+
const zoomFactor = 500;
|
|
673
|
+
const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
|
|
674
|
+
const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
|
|
675
|
+
const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
|
|
676
|
+
const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
|
|
677
|
+
return createComponent(PianoRollContextProvider, {
|
|
678
|
+
get value() {
|
|
679
|
+
return {
|
|
680
|
+
...contextProps
|
|
681
|
+
};
|
|
682
|
+
},
|
|
683
|
+
get children() {
|
|
684
|
+
return createComponent(ScrollZoomViewPort, {
|
|
685
|
+
dimensions: {
|
|
686
|
+
horizontal: () => ({
|
|
687
|
+
pixelOffset: clientRect().left,
|
|
688
|
+
pixelSize: clientRect().width,
|
|
689
|
+
position: contextProps.position,
|
|
690
|
+
range: contextProps.duration,
|
|
691
|
+
zoom: contextProps.zoom * (zoomFactor / clientRect().width),
|
|
692
|
+
onPositionChange: contextProps.onPositionChange,
|
|
693
|
+
onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
|
|
694
|
+
}),
|
|
695
|
+
vertical: () => ({
|
|
696
|
+
pixelOffset: clientRect().top,
|
|
697
|
+
pixelSize: clientRect().height,
|
|
698
|
+
position: contextProps.verticalPosition,
|
|
699
|
+
range: 128,
|
|
700
|
+
zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
|
|
701
|
+
onPositionChange: contextProps.onVerticalPositionChange,
|
|
702
|
+
onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
|
|
703
|
+
})
|
|
704
|
+
},
|
|
705
|
+
get children() {
|
|
706
|
+
const _el$ = _tmpl$2.cloneNode(true),
|
|
707
|
+
_el$2 = _el$.firstChild,
|
|
708
|
+
_el$3 = _el$2.nextSibling,
|
|
709
|
+
_el$4 = _el$3.firstChild;
|
|
710
|
+
_el$.style.setProperty("display", "flex");
|
|
711
|
+
_el$.style.setProperty("flex", "1");
|
|
712
|
+
_el$.style.setProperty("height", "100%");
|
|
713
|
+
_el$.style.setProperty("flex-direction", "row");
|
|
714
|
+
_el$2.style.setProperty("margin-block-start", "0");
|
|
715
|
+
_el$2.style.setProperty("padding-inline-start", "0");
|
|
716
|
+
_el$2.style.setProperty("width", "150px");
|
|
717
|
+
insert(_el$2, createComponent(Index, {
|
|
718
|
+
get each() {
|
|
719
|
+
return allProps.tracks;
|
|
720
|
+
},
|
|
721
|
+
children: track => (() => {
|
|
722
|
+
const _el$6 = _tmpl$3.cloneNode(true);
|
|
723
|
+
_el$6.$$click = () => {
|
|
724
|
+
if (track() === allProps.selectedTrack) {
|
|
725
|
+
allProps.onSelectedTrackChange(undefined);
|
|
726
|
+
} else {
|
|
727
|
+
allProps.onSelectedTrackChange(track());
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
_el$6.style.setProperty("width", "150px");
|
|
731
|
+
_el$6.style.setProperty("height", "30px");
|
|
732
|
+
_el$6.style.setProperty("list-style", "none");
|
|
733
|
+
_el$6.style.setProperty("display", "flex");
|
|
734
|
+
_el$6.style.setProperty("align-items", "center");
|
|
735
|
+
_el$6.style.setProperty("border-top", "1px black solid");
|
|
736
|
+
_el$6.style.setProperty("cursor", "pointer");
|
|
737
|
+
insert(_el$6, () => track().name);
|
|
738
|
+
effect(() => _el$6.style.setProperty("background", track() === allProps.selectedTrack ? "lightgray" : "none"));
|
|
739
|
+
return _el$6;
|
|
740
|
+
})()
|
|
741
|
+
}));
|
|
742
|
+
_el$3.style.setProperty("flex", "1");
|
|
743
|
+
insert(_el$4, createComponent(Show, {
|
|
744
|
+
get when() {
|
|
745
|
+
return !condensed();
|
|
746
|
+
},
|
|
747
|
+
get children() {
|
|
748
|
+
return createComponent(PianoRollKeys, {});
|
|
749
|
+
}
|
|
750
|
+
}), null);
|
|
751
|
+
insert(_el$4, createComponent(ScrollContainer, {
|
|
752
|
+
ref: setScrollerRef,
|
|
753
|
+
get children() {
|
|
754
|
+
const _el$5 = _tmpl$$1.cloneNode(true);
|
|
755
|
+
_el$5.style.setProperty("margin", "0");
|
|
756
|
+
_el$5.style.setProperty("margin-block-start", "0");
|
|
757
|
+
_el$5.style.setProperty("padding-inline-start", "0");
|
|
758
|
+
insert(_el$5, createComponent(Index, {
|
|
759
|
+
get each() {
|
|
760
|
+
return allProps.tracks;
|
|
761
|
+
},
|
|
762
|
+
children: track => {
|
|
763
|
+
const notes = useNotes();
|
|
764
|
+
createEffect(() => {
|
|
765
|
+
notes.onNotesChange(track().notes);
|
|
766
|
+
});
|
|
767
|
+
const [context, setContext] = createStore({
|
|
768
|
+
...contextProps
|
|
769
|
+
});
|
|
770
|
+
createEffect(() => {
|
|
771
|
+
setContext({
|
|
772
|
+
...contextProps,
|
|
773
|
+
condensed: condensed(),
|
|
774
|
+
notes: notes.notes(),
|
|
775
|
+
onNoteChange: notes.onNoteChange,
|
|
776
|
+
onInsertNote: notes.onInsertNote,
|
|
777
|
+
onRemoveNote: notes.onRemoveNote
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
const verticalViewPort = useViewPortDimension("vertical");
|
|
781
|
+
return createComponent(Show, {
|
|
782
|
+
get when() {
|
|
783
|
+
return condensed() || allProps.selectedTrack === track();
|
|
784
|
+
},
|
|
785
|
+
get children() {
|
|
786
|
+
return createComponent(PianoRollContextProvider, {
|
|
787
|
+
value: context,
|
|
788
|
+
get children() {
|
|
789
|
+
const _el$7 = _tmpl$3.cloneNode(true);
|
|
790
|
+
_el$7.style.setProperty("display", "flex");
|
|
791
|
+
_el$7.style.setProperty("position", "relative");
|
|
792
|
+
_el$7.style.setProperty("list-style", "none");
|
|
793
|
+
_el$7.style.setProperty("flex-direction", "row");
|
|
794
|
+
_el$7.style.setProperty("border-top", "1px black solid");
|
|
795
|
+
insert(_el$7, createComponent(PianoRollNotes, {}), null);
|
|
796
|
+
insert(_el$7, createComponent(PianoRollGrid, {}), null);
|
|
797
|
+
effect(() => _el$7.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
|
|
798
|
+
return _el$7;
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}));
|
|
805
|
+
return _el$5;
|
|
806
|
+
}
|
|
807
|
+
}), null);
|
|
808
|
+
insert(_el$4, createComponent(Show, {
|
|
809
|
+
get when() {
|
|
810
|
+
return !condensed();
|
|
811
|
+
},
|
|
812
|
+
get children() {
|
|
813
|
+
return createComponent(VerticalZoomControl, {
|
|
814
|
+
get value() {
|
|
815
|
+
return contextProps.verticalZoom;
|
|
816
|
+
},
|
|
817
|
+
onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}), null);
|
|
821
|
+
insert(_el$3, createComponent(HorizontalZoomControl, {
|
|
822
|
+
style: {
|
|
823
|
+
width: "100%",
|
|
824
|
+
"margin-left": 0
|
|
825
|
+
},
|
|
826
|
+
get value() {
|
|
827
|
+
return contextProps.zoom;
|
|
828
|
+
},
|
|
829
|
+
onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
|
|
830
|
+
}), null);
|
|
831
|
+
effect(_p$ => {
|
|
832
|
+
const _v$ = styles$3.PianoRoll,
|
|
833
|
+
_v$2 = styles$3.PianoRollContainer;
|
|
834
|
+
_v$ !== _p$._v$ && className(_el$3, _p$._v$ = _v$);
|
|
835
|
+
_v$2 !== _p$._v$2 && className(_el$4, _p$._v$2 = _v$2);
|
|
836
|
+
return _p$;
|
|
837
|
+
}, {
|
|
838
|
+
_v$: undefined,
|
|
839
|
+
_v$2: undefined
|
|
840
|
+
});
|
|
841
|
+
return _el$;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
});
|
|
627
846
|
};
|
|
847
|
+
delegateEvents(["click"]);
|
|
628
848
|
|
|
629
849
|
const _tmpl$ = /*#__PURE__*/template(`<div><div></div></div>`, 4);
|
|
630
850
|
const PianoRoll = allProps => {
|
|
631
|
-
const [contextProps, divProps] =
|
|
851
|
+
const [contextProps, divProps] = splitContextProps(allProps);
|
|
632
852
|
const [scrollerRef, setScrollerRef] = createSignal();
|
|
633
853
|
const clientRect = useBoundingClientRect(scrollerRef);
|
|
634
854
|
const zoomFactor = 500;
|
|
@@ -699,33 +919,14 @@ const PianoRoll = allProps => {
|
|
|
699
919
|
|
|
700
920
|
const usePianoRoll = () => {
|
|
701
921
|
const [ppq, onPpqChange] = createSignal(120);
|
|
922
|
+
const [condensed, onCondensedChange] = createSignal(false);
|
|
702
923
|
const [position, onPositionChange] = createSignal(0);
|
|
703
924
|
const [zoom, onZoomChange] = createSignal(10);
|
|
704
925
|
const [verticalZoom, onVerticalZoomChange] = createSignal(5);
|
|
705
926
|
const [verticalPosition, onVerticalPositionChange] = createSignal(64);
|
|
706
927
|
const [gridDivision, onGridDivisionChange] = createSignal(16);
|
|
707
928
|
const [snapToGrid, onSnapToGridChange] = createSignal(true);
|
|
708
|
-
const [notes, onNotesChange] = createSignal([]);
|
|
709
929
|
const [duration, onDurationChange] = createSignal(0);
|
|
710
|
-
const onNoteChange = (index, note) => {
|
|
711
|
-
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
712
|
-
};
|
|
713
|
-
const onInsertNote = note => {
|
|
714
|
-
const index = Math.max(notes().findIndex(({
|
|
715
|
-
ticks
|
|
716
|
-
}) => ticks > note.ticks), 0);
|
|
717
|
-
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
|
|
718
|
-
return index;
|
|
719
|
-
};
|
|
720
|
-
const onRemoveNote = index => {
|
|
721
|
-
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
722
|
-
};
|
|
723
|
-
createEffect(() => {
|
|
724
|
-
const minDuration = Math.max((notes()[notes().length - 1]?.ticks ?? 0) + (notes()[notes().length - 1]?.durationTicks ?? 0), ppq() * 4 * 4);
|
|
725
|
-
if (duration() < minDuration) {
|
|
726
|
-
onDurationChange(minDuration);
|
|
727
|
-
}
|
|
728
|
-
});
|
|
729
930
|
return {
|
|
730
931
|
ppq,
|
|
731
932
|
onPpqChange,
|
|
@@ -741,15 +942,12 @@ const usePianoRoll = () => {
|
|
|
741
942
|
onGridDivisionChange,
|
|
742
943
|
snapToGrid,
|
|
743
944
|
onSnapToGridChange,
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
onNoteChange,
|
|
747
|
-
onInsertNote,
|
|
748
|
-
onRemoveNote,
|
|
945
|
+
condensed,
|
|
946
|
+
onCondensedChange,
|
|
749
947
|
duration,
|
|
750
948
|
onDurationChange
|
|
751
949
|
};
|
|
752
950
|
};
|
|
753
951
|
|
|
754
|
-
export { PianoRoll, usePianoRoll };
|
|
952
|
+
export { MultiTrackPianoRoll, PianoRoll, useNotes, usePianoRoll };
|
|
755
953
|
//# sourceMappingURL=index.js.map
|