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