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/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,14 +199,13 @@ 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
|
-
_el$.$$mousedown =
|
|
204
|
+
_el$.$$mousedown = event => {
|
|
240
205
|
console.log("down");
|
|
241
206
|
setIsMouseDown(true);
|
|
207
|
+
const index = insertOrUpdateNote(event);
|
|
208
|
+
setNewNoteIndex(index);
|
|
242
209
|
};
|
|
243
210
|
const _ref$ = props.ref;
|
|
244
211
|
typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
|
|
@@ -247,14 +214,14 @@ const PianoRollNotes = props => {
|
|
|
247
214
|
return context.notes;
|
|
248
215
|
},
|
|
249
216
|
children: (note, index) => {
|
|
250
|
-
const
|
|
217
|
+
const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
|
|
251
218
|
const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
|
|
252
219
|
return createComponent(Show, {
|
|
253
220
|
get when() {
|
|
254
|
-
return memo(() =>
|
|
221
|
+
return memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
|
|
255
222
|
},
|
|
256
223
|
get children() {
|
|
257
|
-
const _el$2 = _tmpl$$
|
|
224
|
+
const _el$2 = _tmpl$$6.cloneNode(true);
|
|
258
225
|
_el$2.$$mousedown = event => {
|
|
259
226
|
event.stopPropagation();
|
|
260
227
|
setIsDragging(true);
|
|
@@ -264,7 +231,7 @@ const PianoRollNotes = props => {
|
|
|
264
231
|
const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
|
|
265
232
|
context.onNoteChange?.(index, {
|
|
266
233
|
...note(),
|
|
267
|
-
...(noteDragMode() === "move" && {
|
|
234
|
+
...(noteDragMode() === "move" && !context.condensed && {
|
|
268
235
|
midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
|
|
269
236
|
}),
|
|
270
237
|
...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
|
|
@@ -300,38 +267,37 @@ const PianoRollNotes = props => {
|
|
|
300
267
|
};
|
|
301
268
|
effect(_p$ => {
|
|
302
269
|
const _v$ = getClasses(noteDragMode()).join(" "),
|
|
303
|
-
_v$2 =
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
270
|
+
_v$2 = {
|
|
271
|
+
"background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
|
|
272
|
+
...(context.condensed ? {
|
|
273
|
+
top: 0,
|
|
274
|
+
height: "100%"
|
|
275
|
+
} : {
|
|
276
|
+
top: `${verticalVirtualDimensions().offset}px`,
|
|
277
|
+
height: `${verticalVirtualDimensions().size}px`
|
|
278
|
+
}),
|
|
279
|
+
left: `${horizontalDimensions().offset}px`,
|
|
280
|
+
width: `${horizontalDimensions().size}px`
|
|
281
|
+
};
|
|
308
282
|
_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);
|
|
283
|
+
_p$._v$2 = style(_el$2, _v$2, _p$._v$2);
|
|
314
284
|
return _p$;
|
|
315
285
|
}, {
|
|
316
286
|
_v$: undefined,
|
|
317
|
-
_v$2: undefined
|
|
318
|
-
_v$3: undefined,
|
|
319
|
-
_v$4: undefined,
|
|
320
|
-
_v$5: undefined,
|
|
321
|
-
_v$6: undefined
|
|
287
|
+
_v$2: undefined
|
|
322
288
|
});
|
|
323
289
|
return _el$2;
|
|
324
290
|
}
|
|
325
291
|
});
|
|
326
292
|
}
|
|
327
293
|
}));
|
|
328
|
-
effect(() => className(_el$, styles$
|
|
294
|
+
effect(() => className(_el$, styles$2.PianoRollNotes));
|
|
329
295
|
return _el$;
|
|
330
296
|
})();
|
|
331
297
|
};
|
|
332
298
|
delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
|
|
333
299
|
|
|
334
|
-
const _tmpl$$
|
|
300
|
+
const _tmpl$$5 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
|
|
335
301
|
const ScrollContainer = props => {
|
|
336
302
|
let scrollContentRef;
|
|
337
303
|
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
@@ -393,7 +359,7 @@ const ScrollContainer = props => {
|
|
|
393
359
|
});
|
|
394
360
|
});
|
|
395
361
|
return (() => {
|
|
396
|
-
const _el$ = _tmpl$$
|
|
362
|
+
const _el$ = _tmpl$$5.cloneNode(true),
|
|
397
363
|
_el$2 = _el$.firstChild,
|
|
398
364
|
_el$3 = _el$2.firstChild,
|
|
399
365
|
_el$4 = _el$3.firstChild;
|
|
@@ -434,6 +400,69 @@ const ScrollContainer = props => {
|
|
|
434
400
|
})();
|
|
435
401
|
};
|
|
436
402
|
|
|
403
|
+
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";
|
|
404
|
+
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"};
|
|
405
|
+
styleInject(css_248z$1);
|
|
406
|
+
|
|
407
|
+
const _tmpl$$4 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
408
|
+
const PianoRollKeys = () => {
|
|
409
|
+
const viewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
410
|
+
return (() => {
|
|
411
|
+
const _el$ = _tmpl$$4.cloneNode(true);
|
|
412
|
+
insert(_el$, createComponent(Index, {
|
|
413
|
+
each: keys,
|
|
414
|
+
children: key => {
|
|
415
|
+
const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
|
|
416
|
+
return createComponent(Show, {
|
|
417
|
+
get when() {
|
|
418
|
+
return virtualDimensions().size > 0;
|
|
419
|
+
},
|
|
420
|
+
get children() {
|
|
421
|
+
const _el$2 = _tmpl$$4.cloneNode(true);
|
|
422
|
+
effect(_p$ => {
|
|
423
|
+
const _v$ = {
|
|
424
|
+
[styles$1["Key"]]: true,
|
|
425
|
+
[styles$1["black"]]: key().isBlack,
|
|
426
|
+
[styles$1["white"]]: !key().isBlack,
|
|
427
|
+
[styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
|
|
428
|
+
[styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
|
|
429
|
+
},
|
|
430
|
+
_v$2 = key().name,
|
|
431
|
+
_v$3 = key().number % 12,
|
|
432
|
+
_v$4 = `${virtualDimensions().offset}px`,
|
|
433
|
+
_v$5 = `${virtualDimensions().size}px`;
|
|
434
|
+
_p$._v$ = classList(_el$2, _v$, _p$._v$);
|
|
435
|
+
_v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
|
|
436
|
+
_v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
|
|
437
|
+
_v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
|
|
438
|
+
_v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
|
|
439
|
+
return _p$;
|
|
440
|
+
}, {
|
|
441
|
+
_v$: undefined,
|
|
442
|
+
_v$2: undefined,
|
|
443
|
+
_v$3: undefined,
|
|
444
|
+
_v$4: undefined,
|
|
445
|
+
_v$5: undefined
|
|
446
|
+
});
|
|
447
|
+
return _el$2;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}));
|
|
452
|
+
effect(() => className(_el$, styles$1.PianoRollKeys));
|
|
453
|
+
return _el$;
|
|
454
|
+
})();
|
|
455
|
+
};
|
|
456
|
+
const blackKeys = [1, 3, 6, 8, 10];
|
|
457
|
+
const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
458
|
+
const keys = Array.from({
|
|
459
|
+
length: 128
|
|
460
|
+
}).map((_, index) => ({
|
|
461
|
+
number: index,
|
|
462
|
+
name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
|
|
463
|
+
isBlack: blackKeys.includes(index % 12)
|
|
464
|
+
}));
|
|
465
|
+
|
|
437
466
|
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
467
|
var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
|
|
439
468
|
styleInject(css_248z);
|
|
@@ -550,6 +579,30 @@ const PianoRollGrid = () => {
|
|
|
550
579
|
})();
|
|
551
580
|
};
|
|
552
581
|
|
|
582
|
+
const useNotes = () => {
|
|
583
|
+
const [notes, onNotesChange] = createSignal([]);
|
|
584
|
+
const onNoteChange = (index, note) => {
|
|
585
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
586
|
+
};
|
|
587
|
+
const onInsertNote = note => {
|
|
588
|
+
const index = Math.max(notes().findIndex(({
|
|
589
|
+
ticks
|
|
590
|
+
}) => ticks > note.ticks), 0);
|
|
591
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
|
|
592
|
+
return index;
|
|
593
|
+
};
|
|
594
|
+
const onRemoveNote = index => {
|
|
595
|
+
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
596
|
+
};
|
|
597
|
+
return {
|
|
598
|
+
notes,
|
|
599
|
+
onNotesChange,
|
|
600
|
+
onNoteChange,
|
|
601
|
+
onInsertNote,
|
|
602
|
+
onRemoveNote
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
|
|
553
606
|
const defaultRect = {
|
|
554
607
|
left: 0,
|
|
555
608
|
width: 0,
|
|
@@ -606,29 +659,198 @@ const VerticalZoomControl = props => {
|
|
|
606
659
|
})();
|
|
607
660
|
};
|
|
608
661
|
|
|
609
|
-
const _tmpl$$1 = /*#__PURE__*/template(`<
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
662
|
+
const _tmpl$$1 = /*#__PURE__*/template(`<ul></ul>`, 2),
|
|
663
|
+
_tmpl$2 = /*#__PURE__*/template(`<div><ul></ul><div><div></div></div></div>`, 8),
|
|
664
|
+
_tmpl$3 = /*#__PURE__*/template(`<li></li>`, 2);
|
|
665
|
+
const MultiTrackPianoRoll = allProps => {
|
|
666
|
+
const condensed = createMemo(() => !allProps.selectedTrack);
|
|
667
|
+
const [ownProps, restProps] = splitProps(allProps, ["tracks", "selectedTrack"]);
|
|
668
|
+
const [contextProps, divProps] = splitContextProps(mergeProps$1(restProps, {
|
|
669
|
+
notes: [],
|
|
670
|
+
condensed: false
|
|
671
|
+
}));
|
|
672
|
+
const [scrollerRef, setScrollerRef] = createSignal();
|
|
673
|
+
const clientRect = useBoundingClientRect(scrollerRef);
|
|
674
|
+
const zoomFactor = 500;
|
|
675
|
+
const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
|
|
676
|
+
const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
|
|
677
|
+
const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
|
|
678
|
+
const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
|
|
679
|
+
return createComponent(PianoRollContextProvider, {
|
|
680
|
+
get value() {
|
|
681
|
+
return {
|
|
682
|
+
...contextProps
|
|
683
|
+
};
|
|
684
|
+
},
|
|
685
|
+
get children() {
|
|
686
|
+
return createComponent(ScrollZoomViewPort, {
|
|
687
|
+
dimensions: {
|
|
688
|
+
horizontal: () => ({
|
|
689
|
+
pixelOffset: clientRect().left,
|
|
690
|
+
pixelSize: clientRect().width,
|
|
691
|
+
position: contextProps.position,
|
|
692
|
+
range: contextProps.duration,
|
|
693
|
+
zoom: contextProps.zoom * (zoomFactor / clientRect().width),
|
|
694
|
+
onPositionChange: contextProps.onPositionChange,
|
|
695
|
+
onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
|
|
696
|
+
}),
|
|
697
|
+
vertical: () => ({
|
|
698
|
+
pixelOffset: clientRect().top,
|
|
699
|
+
pixelSize: clientRect().height,
|
|
700
|
+
position: contextProps.verticalPosition,
|
|
701
|
+
range: 128,
|
|
702
|
+
zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
|
|
703
|
+
onPositionChange: contextProps.onVerticalPositionChange,
|
|
704
|
+
onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
|
|
705
|
+
})
|
|
706
|
+
},
|
|
707
|
+
get children() {
|
|
708
|
+
const _el$ = _tmpl$2.cloneNode(true),
|
|
709
|
+
_el$2 = _el$.firstChild,
|
|
710
|
+
_el$3 = _el$2.nextSibling,
|
|
711
|
+
_el$4 = _el$3.firstChild;
|
|
712
|
+
_el$.style.setProperty("display", "flex");
|
|
713
|
+
_el$.style.setProperty("flex", "1");
|
|
714
|
+
_el$.style.setProperty("height", "100%");
|
|
715
|
+
_el$.style.setProperty("flex-direction", "row");
|
|
716
|
+
_el$2.style.setProperty("margin-block-start", "0");
|
|
717
|
+
_el$2.style.setProperty("padding-inline-start", "0");
|
|
718
|
+
_el$2.style.setProperty("width", "150px");
|
|
719
|
+
insert(_el$2, createComponent(Index, {
|
|
720
|
+
get each() {
|
|
721
|
+
return allProps.tracks;
|
|
722
|
+
},
|
|
723
|
+
children: track => (() => {
|
|
724
|
+
const _el$6 = _tmpl$3.cloneNode(true);
|
|
725
|
+
_el$6.$$click = () => {
|
|
726
|
+
if (track() === allProps.selectedTrack) {
|
|
727
|
+
allProps.onSelectedTrackChange(undefined);
|
|
728
|
+
} else {
|
|
729
|
+
allProps.onSelectedTrackChange(track());
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
_el$6.style.setProperty("width", "150px");
|
|
733
|
+
_el$6.style.setProperty("height", "30px");
|
|
734
|
+
_el$6.style.setProperty("list-style", "none");
|
|
735
|
+
_el$6.style.setProperty("display", "flex");
|
|
736
|
+
_el$6.style.setProperty("align-items", "center");
|
|
737
|
+
_el$6.style.setProperty("border-top", "1px black solid");
|
|
738
|
+
_el$6.style.setProperty("cursor", "pointer");
|
|
739
|
+
insert(_el$6, () => track().name);
|
|
740
|
+
effect(() => _el$6.style.setProperty("background", track() === allProps.selectedTrack ? "lightgray" : "none"));
|
|
741
|
+
return _el$6;
|
|
742
|
+
})()
|
|
743
|
+
}));
|
|
744
|
+
_el$3.style.setProperty("flex", "1");
|
|
745
|
+
insert(_el$4, createComponent(Show, {
|
|
746
|
+
get when() {
|
|
747
|
+
return !condensed();
|
|
748
|
+
},
|
|
749
|
+
get children() {
|
|
750
|
+
return createComponent(PianoRollKeys, {});
|
|
751
|
+
}
|
|
752
|
+
}), null);
|
|
753
|
+
insert(_el$4, createComponent(ScrollContainer, {
|
|
754
|
+
ref: setScrollerRef,
|
|
755
|
+
get children() {
|
|
756
|
+
const _el$5 = _tmpl$$1.cloneNode(true);
|
|
757
|
+
_el$5.style.setProperty("margin", "0");
|
|
758
|
+
_el$5.style.setProperty("margin-block-start", "0");
|
|
759
|
+
_el$5.style.setProperty("padding-inline-start", "0");
|
|
760
|
+
insert(_el$5, createComponent(Index, {
|
|
761
|
+
get each() {
|
|
762
|
+
return allProps.tracks;
|
|
763
|
+
},
|
|
764
|
+
children: track => {
|
|
765
|
+
const notes = useNotes();
|
|
766
|
+
createEffect(() => {
|
|
767
|
+
notes.onNotesChange(track().notes);
|
|
768
|
+
});
|
|
769
|
+
const [context, setContext] = createStore({
|
|
770
|
+
...contextProps
|
|
771
|
+
});
|
|
772
|
+
createEffect(() => {
|
|
773
|
+
setContext({
|
|
774
|
+
...contextProps,
|
|
775
|
+
condensed: condensed(),
|
|
776
|
+
notes: notes.notes(),
|
|
777
|
+
onNoteChange: notes.onNoteChange,
|
|
778
|
+
onInsertNote: notes.onInsertNote,
|
|
779
|
+
onRemoveNote: notes.onRemoveNote
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
const verticalViewPort = useViewPortDimension("vertical");
|
|
783
|
+
return createComponent(Show, {
|
|
784
|
+
get when() {
|
|
785
|
+
return condensed() || allProps.selectedTrack === track();
|
|
786
|
+
},
|
|
787
|
+
get children() {
|
|
788
|
+
return createComponent(PianoRollContextProvider, {
|
|
789
|
+
value: context,
|
|
790
|
+
get children() {
|
|
791
|
+
const _el$7 = _tmpl$3.cloneNode(true);
|
|
792
|
+
_el$7.style.setProperty("display", "flex");
|
|
793
|
+
_el$7.style.setProperty("position", "relative");
|
|
794
|
+
_el$7.style.setProperty("list-style", "none");
|
|
795
|
+
_el$7.style.setProperty("flex-direction", "row");
|
|
796
|
+
_el$7.style.setProperty("border-top", "1px black solid");
|
|
797
|
+
insert(_el$7, createComponent(PianoRollNotes, {}), null);
|
|
798
|
+
insert(_el$7, createComponent(PianoRollGrid, {}), null);
|
|
799
|
+
effect(() => _el$7.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
|
|
800
|
+
return _el$7;
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
}));
|
|
807
|
+
return _el$5;
|
|
808
|
+
}
|
|
809
|
+
}), null);
|
|
810
|
+
insert(_el$4, createComponent(Show, {
|
|
811
|
+
get when() {
|
|
812
|
+
return !condensed();
|
|
813
|
+
},
|
|
814
|
+
get children() {
|
|
815
|
+
return createComponent(VerticalZoomControl, {
|
|
816
|
+
get value() {
|
|
817
|
+
return contextProps.verticalZoom;
|
|
818
|
+
},
|
|
819
|
+
onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
}), null);
|
|
823
|
+
insert(_el$3, createComponent(HorizontalZoomControl, {
|
|
824
|
+
style: {
|
|
825
|
+
width: "100%",
|
|
826
|
+
"margin-left": 0
|
|
827
|
+
},
|
|
828
|
+
get value() {
|
|
829
|
+
return contextProps.zoom;
|
|
830
|
+
},
|
|
831
|
+
onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
|
|
832
|
+
}), null);
|
|
833
|
+
effect(_p$ => {
|
|
834
|
+
const _v$ = styles$3.PianoRoll,
|
|
835
|
+
_v$2 = styles$3.PianoRollContainer;
|
|
836
|
+
_v$ !== _p$._v$ && className(_el$3, _p$._v$ = _v$);
|
|
837
|
+
_v$2 !== _p$._v$2 && className(_el$4, _p$._v$2 = _v$2);
|
|
838
|
+
return _p$;
|
|
839
|
+
}, {
|
|
840
|
+
_v$: undefined,
|
|
841
|
+
_v$2: undefined
|
|
842
|
+
});
|
|
843
|
+
return _el$;
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
});
|
|
627
848
|
};
|
|
849
|
+
delegateEvents(["click"]);
|
|
628
850
|
|
|
629
851
|
const _tmpl$ = /*#__PURE__*/template(`<div><div></div></div>`, 4);
|
|
630
852
|
const PianoRoll = allProps => {
|
|
631
|
-
const [contextProps, divProps] =
|
|
853
|
+
const [contextProps, divProps] = splitContextProps(allProps);
|
|
632
854
|
const [scrollerRef, setScrollerRef] = createSignal();
|
|
633
855
|
const clientRect = useBoundingClientRect(scrollerRef);
|
|
634
856
|
const zoomFactor = 500;
|
|
@@ -699,33 +921,14 @@ const PianoRoll = allProps => {
|
|
|
699
921
|
|
|
700
922
|
const usePianoRoll = () => {
|
|
701
923
|
const [ppq, onPpqChange] = createSignal(120);
|
|
924
|
+
const [condensed, onCondensedChange] = createSignal(false);
|
|
702
925
|
const [position, onPositionChange] = createSignal(0);
|
|
703
926
|
const [zoom, onZoomChange] = createSignal(10);
|
|
704
927
|
const [verticalZoom, onVerticalZoomChange] = createSignal(5);
|
|
705
928
|
const [verticalPosition, onVerticalPositionChange] = createSignal(64);
|
|
706
|
-
const [gridDivision, onGridDivisionChange] = createSignal(
|
|
929
|
+
const [gridDivision, onGridDivisionChange] = createSignal(4);
|
|
707
930
|
const [snapToGrid, onSnapToGridChange] = createSignal(true);
|
|
708
|
-
const [notes, onNotesChange] = createSignal([]);
|
|
709
931
|
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
932
|
return {
|
|
730
933
|
ppq,
|
|
731
934
|
onPpqChange,
|
|
@@ -741,15 +944,12 @@ const usePianoRoll = () => {
|
|
|
741
944
|
onGridDivisionChange,
|
|
742
945
|
snapToGrid,
|
|
743
946
|
onSnapToGridChange,
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
onNoteChange,
|
|
747
|
-
onInsertNote,
|
|
748
|
-
onRemoveNote,
|
|
947
|
+
condensed,
|
|
948
|
+
onCondensedChange,
|
|
749
949
|
duration,
|
|
750
950
|
onDurationChange
|
|
751
951
|
};
|
|
752
952
|
};
|
|
753
953
|
|
|
754
|
-
export { PianoRoll, usePianoRoll };
|
|
954
|
+
export { MultiTrackPianoRoll, PianoRoll, useNotes, usePianoRoll };
|
|
755
955
|
//# sourceMappingURL=index.js.map
|