solid-pianoroll 0.0.9 → 0.0.10
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 +458 -456
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +460 -458
- package/dist/esm/index.js.map +1 -1
- package/dist/source/PianoRoll.jsx +53 -27
- package/dist/source/PianoRollContext.jsx +3 -42
- package/dist/source/PianoRollGrid.jsx +18 -33
- package/dist/source/PianoRollKeys.jsx +10 -6
- package/dist/source/PianoRollNotes.jsx +91 -46
- package/dist/source/usePianoRoll.js +6 -3
- package/dist/source/viewport/HorizontalZoomControl.jsx +9 -0
- package/dist/source/viewport/ScrollContainer.jsx +87 -0
- package/dist/source/viewport/ScrollZoomViewPort.jsx +19 -0
- package/dist/source/viewport/VerticalZoomControl.jsx +12 -0
- package/dist/source/viewport/createViewPortDimension.js +39 -0
- package/dist/types/PianoRoll.d.ts +1 -1
- package/dist/types/PianoRollContext.d.ts +2 -22
- package/dist/types/PianoRollNotes.d.ts +1 -1
- package/dist/types/usePianoRoll.d.ts +1 -0
- package/dist/types/viewport/HorizontalZoomControl.d.ts +3 -0
- package/dist/types/viewport/ScrollContainer.d.ts +5 -0
- package/dist/types/viewport/ScrollZoomViewPort.d.ts +23 -0
- package/dist/types/viewport/VerticalZoomControl.d.ts +3 -0
- package/dist/types/viewport/createViewPortDimension.d.ts +31 -0
- package/package.json +7 -1
- package/dist/source/HorizontalZoomControl.jsx +0 -9
- package/dist/source/ScrollContainer.jsx +0 -138
- package/dist/source/VerticalZoomControl.jsx +0 -12
- package/dist/source/useViewPortScaler.js +0 -44
- package/dist/types/HorizontalZoomControl.d.ts +0 -2
- package/dist/types/ScrollContainer.d.ts +0 -5
- package/dist/types/VerticalZoomControl.d.ts +0 -2
- package/dist/types/useViewPortScaler.d.ts +0 -20
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createComponent,
|
|
2
|
-
import {
|
|
1
|
+
import { createComponent, insert, effect, classList, setAttribute, className, template, delegateEvents, use, memo, spread, mergeProps } from 'solid-js/web';
|
|
2
|
+
import { createContext, useContext, createEffect, createMemo, Index, Show, createSignal, splitProps } from 'solid-js';
|
|
3
3
|
import { createStore } from 'solid-js/store';
|
|
4
4
|
|
|
5
5
|
function styleInject(css, ref) {
|
|
@@ -27,198 +27,132 @@ function styleInject(css, ref) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
var css_248z$
|
|
31
|
-
var styles$
|
|
32
|
-
styleInject(css_248z$
|
|
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 padding-top: 16px;\n padding-left: 16px;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
|
|
31
|
+
var styles$3 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
|
|
32
|
+
styleInject(css_248z$3);
|
|
33
33
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
right: 0,
|
|
41
|
-
x: 0,
|
|
42
|
-
y: 0
|
|
34
|
+
const PianoRollContext = createContext();
|
|
35
|
+
const PianoRollContextProvider = PianoRollContext.Provider;
|
|
36
|
+
const usePianoRollContext = () => {
|
|
37
|
+
const context = useContext(PianoRollContext);
|
|
38
|
+
if (!context) throw new Error("No PianoRollContext found");
|
|
39
|
+
return context;
|
|
43
40
|
};
|
|
44
|
-
function useBoundingClientRect(containerRef) {
|
|
45
|
-
const [boundingClientRect, setBoundingClientRect] = createSignal(defaultRect);
|
|
46
|
-
createEffect(() => {
|
|
47
|
-
const container = containerRef();
|
|
48
|
-
if (!container) return;
|
|
49
|
-
const updateBoundingClientRect = () => {
|
|
50
|
-
setBoundingClientRect(container.getBoundingClientRect() ?? defaultRect);
|
|
51
|
-
};
|
|
52
|
-
const resizeObserver = new ResizeObserver(updateBoundingClientRect);
|
|
53
|
-
resizeObserver.observe(container);
|
|
54
|
-
updateBoundingClientRect();
|
|
55
|
-
return () => {
|
|
56
|
-
resizeObserver.disconnect();
|
|
57
|
-
};
|
|
58
|
-
});
|
|
59
|
-
return boundingClientRect;
|
|
60
|
-
}
|
|
61
41
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
42
|
+
var css_248z$2 = ".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";
|
|
43
|
+
var styles$2 = {"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"};
|
|
44
|
+
styleInject(css_248z$2);
|
|
45
|
+
|
|
46
|
+
function createViewPortDimension(getState) {
|
|
47
|
+
const getStateWithFunctions = () => ({
|
|
48
|
+
...getState(),
|
|
49
|
+
calculatePixelValue,
|
|
50
|
+
calculatePosition,
|
|
51
|
+
calculatePixelDimensions,
|
|
52
|
+
calculateVisibleRange,
|
|
53
|
+
calculateMaxPosition
|
|
54
|
+
});
|
|
55
|
+
const [state, setState] = createStore(getStateWithFunctions());
|
|
56
|
+
createEffect(() => setState(getStateWithFunctions()));
|
|
57
|
+
function calculatePixelValue(position = state.position) {
|
|
58
|
+
const virtualSize = state.pixelSize * state.zoom;
|
|
59
|
+
return position / state.range * virtualSize;
|
|
70
60
|
}
|
|
71
|
-
function
|
|
72
|
-
return
|
|
61
|
+
function calculatePixelOffset(position) {
|
|
62
|
+
return calculatePixelValue(position) - calculatePixelValue(state.position);
|
|
73
63
|
}
|
|
74
|
-
function
|
|
75
|
-
const percentX = (offset - state
|
|
76
|
-
const position = state
|
|
64
|
+
function calculatePosition(offset) {
|
|
65
|
+
const percentX = (offset - state.pixelOffset) / state.pixelSize;
|
|
66
|
+
const position = state.position + percentX * calculateVisibleRange();
|
|
77
67
|
return position;
|
|
78
68
|
}
|
|
79
|
-
function
|
|
80
|
-
return state
|
|
69
|
+
function calculateVisibleRange() {
|
|
70
|
+
return state.range / state.zoom;
|
|
81
71
|
}
|
|
82
|
-
function
|
|
83
|
-
return
|
|
72
|
+
function calculateMaxPosition() {
|
|
73
|
+
return state.range - state.range / state.zoom;
|
|
84
74
|
}
|
|
85
|
-
function
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const offset = clamp(virtualLeft, 0, state().viewPortSize);
|
|
89
|
-
const size = clamp(virtualWidth - (offset - virtualLeft), 0, state().viewPortSize - offset);
|
|
75
|
+
function calculatePixelDimensions(position, length) {
|
|
76
|
+
const offset = calculatePixelOffset(position);
|
|
77
|
+
const size = calculatePixelValue(length);
|
|
90
78
|
return {
|
|
91
79
|
offset,
|
|
92
80
|
size
|
|
93
81
|
};
|
|
94
82
|
}
|
|
95
|
-
return
|
|
96
|
-
getScaledValue,
|
|
97
|
-
getCoordinates,
|
|
98
|
-
getPosition,
|
|
99
|
-
getVirtualDimensions,
|
|
100
|
-
getVisibleRange,
|
|
101
|
-
getMaxPosition,
|
|
102
|
-
getScrollSize
|
|
103
|
-
};
|
|
83
|
+
return state;
|
|
104
84
|
}
|
|
105
|
-
const clamp = (value, min, max) =>
|
|
106
|
-
return Math.max(min, Math.min(max, value));
|
|
107
|
-
};
|
|
85
|
+
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
108
86
|
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
virtualRange: props.duration,
|
|
120
|
-
zoom: props.zoom * (500 / clientRect().width)
|
|
121
|
-
}));
|
|
122
|
-
const verticalViewPort = useViewPortScaler(() => ({
|
|
123
|
-
viewPortOffset: clientRect().top,
|
|
124
|
-
viewPortSize: clientRect().height,
|
|
125
|
-
virtualPosition: props.verticalPosition,
|
|
126
|
-
zoom: props.verticalZoom * (500 / clientRect().height),
|
|
127
|
-
virtualRange: 128
|
|
128
|
-
}));
|
|
129
|
-
const getContextValue = () => {
|
|
130
|
-
return {
|
|
131
|
-
...contextProps,
|
|
132
|
-
horizontalViewPort,
|
|
133
|
-
verticalViewPort,
|
|
134
|
-
clientRect: clientRect(),
|
|
135
|
-
isDragging: isDragging(),
|
|
136
|
-
onIsDraggingChange: setIsDragging,
|
|
137
|
-
noteDragMode: noteDragMode(),
|
|
138
|
-
onNoteDragModeChange: setNoteDragMode
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
const [contextValue, setContextValue] = createStore(getContextValue());
|
|
142
|
-
createEffect(() => {
|
|
143
|
-
setContextValue(getContextValue());
|
|
144
|
-
});
|
|
145
|
-
return createComponent(PianoRollContext.Provider, {
|
|
146
|
-
value: contextValue,
|
|
87
|
+
const ScrollZoomViewPort = props => {
|
|
88
|
+
const viewPorts = Object.entries(props.dimensions).map(([name, viewPortProps]) => createViewPortDimension(() => ({
|
|
89
|
+
name: name,
|
|
90
|
+
...viewPortProps()
|
|
91
|
+
})));
|
|
92
|
+
const parentViewPorts = useContext(ScrollZoomViewPortContext);
|
|
93
|
+
return createComponent(ScrollZoomViewPortContext.Provider, {
|
|
94
|
+
get value() {
|
|
95
|
+
return [...parentViewPorts, ...viewPorts];
|
|
96
|
+
},
|
|
147
97
|
get children() {
|
|
148
98
|
return props.children;
|
|
149
99
|
}
|
|
150
100
|
});
|
|
151
101
|
};
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const _tmpl$$6 = /*#__PURE__*/template(`<input type="range" max="500" min="1" step="0.01">`, 1);
|
|
159
|
-
const HorizontalZoomControl = () => {
|
|
160
|
-
const context = usePianoRollContext();
|
|
161
|
-
return (() => {
|
|
162
|
-
const _el$ = _tmpl$$6.cloneNode(true);
|
|
163
|
-
_el$.$$input = event => context.onZoomChange?.(event.currentTarget.valueAsNumber);
|
|
164
|
-
_el$.style.setProperty("margin-left", "50px");
|
|
165
|
-
_el$.style.setProperty("margin-right", "16px");
|
|
166
|
-
effect(() => _el$.value = context.zoom);
|
|
167
|
-
return _el$;
|
|
168
|
-
})();
|
|
102
|
+
const ScrollZoomViewPortContext = createContext([]);
|
|
103
|
+
const useViewPortDimension = name => {
|
|
104
|
+
const viewPorts = useContext(ScrollZoomViewPortContext);
|
|
105
|
+
const viewPort = name ? viewPorts.find(viewPort => viewPort.name === name) : viewPorts[viewPorts.length - 1];
|
|
106
|
+
if (!viewPort) throw new Error(`ViewPort dimension "${name}" not found.`);
|
|
107
|
+
return viewPort;
|
|
169
108
|
};
|
|
170
|
-
delegateEvents(["input"]);
|
|
171
109
|
|
|
172
|
-
|
|
173
|
-
var styles = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","PianoRollKeys-Key":"PianoRollKeys-module_PianoRollKeys-Key__xunQt"};
|
|
174
|
-
styleInject(css_248z);
|
|
175
|
-
|
|
176
|
-
const _tmpl$$5 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
110
|
+
const _tmpl$$6 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
177
111
|
const PianoRollKeys = () => {
|
|
178
|
-
const
|
|
112
|
+
const viewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
179
113
|
return (() => {
|
|
180
|
-
const _el$ = _tmpl$$
|
|
114
|
+
const _el$ = _tmpl$$6.cloneNode(true);
|
|
181
115
|
insert(_el$, createComponent(Index, {
|
|
182
116
|
each: keys,
|
|
183
117
|
children: key => {
|
|
184
|
-
const virtualDimensions = createMemo(() =>
|
|
118
|
+
const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
|
|
185
119
|
return createComponent(Show, {
|
|
186
120
|
get when() {
|
|
187
121
|
return virtualDimensions().size > 0;
|
|
188
122
|
},
|
|
189
123
|
get children() {
|
|
190
|
-
const _el$2 = _tmpl$$
|
|
124
|
+
const _el$2 = _tmpl$$6.cloneNode(true);
|
|
191
125
|
effect(_p$ => {
|
|
192
|
-
const _v$ =
|
|
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
|
+
},
|
|
193
133
|
_v$2 = key().name,
|
|
194
134
|
_v$3 = key().number % 12,
|
|
195
135
|
_v$4 = `${virtualDimensions().offset}px`,
|
|
196
|
-
_v$5 = `${virtualDimensions().size}px
|
|
197
|
-
|
|
198
|
-
_v$7 = `${!key().isBlack && !blackKeys.includes((key().number + 1) % 12) ? "0.1px" : 0} 1px ${!key().isBlack && !blackKeys.includes((key().number - 1) % 12) ? "0.1px" : 0} 0`;
|
|
199
|
-
_v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
|
|
136
|
+
_v$5 = `${virtualDimensions().size}px`;
|
|
137
|
+
_p$._v$ = classList(_el$2, _v$, _p$._v$);
|
|
200
138
|
_v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
|
|
201
139
|
_v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
|
|
202
140
|
_v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
|
|
203
141
|
_v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
|
|
204
|
-
_v$6 !== _p$._v$6 && _el$2.style.setProperty("background-color", _p$._v$6 = _v$6);
|
|
205
|
-
_v$7 !== _p$._v$7 && _el$2.style.setProperty("border-width", _p$._v$7 = _v$7);
|
|
206
142
|
return _p$;
|
|
207
143
|
}, {
|
|
208
144
|
_v$: undefined,
|
|
209
145
|
_v$2: undefined,
|
|
210
146
|
_v$3: undefined,
|
|
211
147
|
_v$4: undefined,
|
|
212
|
-
_v$5: undefined
|
|
213
|
-
_v$6: undefined,
|
|
214
|
-
_v$7: undefined
|
|
148
|
+
_v$5: undefined
|
|
215
149
|
});
|
|
216
150
|
return _el$2;
|
|
217
151
|
}
|
|
218
152
|
});
|
|
219
153
|
}
|
|
220
154
|
}));
|
|
221
|
-
effect(() => className(_el$, styles.PianoRollKeys));
|
|
155
|
+
effect(() => className(_el$, styles$2.PianoRollKeys));
|
|
222
156
|
return _el$;
|
|
223
157
|
})();
|
|
224
158
|
};
|
|
@@ -232,149 +166,186 @@ const keys = Array.from({
|
|
|
232
166
|
isBlack: blackKeys.includes(index % 12)
|
|
233
167
|
}));
|
|
234
168
|
|
|
235
|
-
|
|
236
|
-
|
|
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);
|
|
172
|
+
|
|
173
|
+
const _tmpl$$5 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
237
174
|
const PianoRollNotes = props => {
|
|
238
175
|
const context = usePianoRollContext();
|
|
176
|
+
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
177
|
+
const horizontalViewPort = createMemo(() => useViewPortDimension("horizontal"));
|
|
239
178
|
const gridDivisionTicks = createMemo(() => context.ppq * 4 / context.gridDivision);
|
|
240
179
|
const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
|
|
180
|
+
const insertOrUpdateNote = event => {
|
|
181
|
+
const position = horizontalViewPort().calculatePosition(event.clientX);
|
|
182
|
+
const midi = 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
|
|
183
|
+
const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
|
|
184
|
+
const velocity = 127;
|
|
185
|
+
const existingNote = newNote();
|
|
186
|
+
const ticks = existingNote?.ticks ?? eventPositionTicks;
|
|
187
|
+
const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisionTicks();
|
|
188
|
+
const note = {
|
|
189
|
+
midi,
|
|
190
|
+
ticks,
|
|
191
|
+
durationTicks,
|
|
192
|
+
velocity
|
|
193
|
+
};
|
|
194
|
+
if (existingNote) {
|
|
195
|
+
context.onNoteChange?.(newNoteIndex(), note);
|
|
196
|
+
return newNoteIndex();
|
|
197
|
+
} else {
|
|
198
|
+
return context.onInsertNote?.(note) ?? -1;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const [isDragging, setIsDragging] = createSignal(false);
|
|
202
|
+
const [noteDragMode, setNoteDragMode] = createSignal();
|
|
203
|
+
const [newNoteIndex, setNewNoteIndex] = createSignal(-1);
|
|
204
|
+
const [isMouseDown, setIsMouseDown] = createSignal(false);
|
|
205
|
+
const newNote = createMemo(() => context.notes[newNoteIndex()]);
|
|
206
|
+
const getClasses = noteDragMode => {
|
|
207
|
+
return noteDragMode ? [styles$1.Note, styles$1[noteDragMode]] : [styles$1.Note];
|
|
208
|
+
};
|
|
241
209
|
return (() => {
|
|
242
|
-
const _el$ = _tmpl$$
|
|
243
|
-
|
|
244
|
-
|
|
210
|
+
const _el$ = _tmpl$$5.cloneNode(true);
|
|
211
|
+
_el$.$$click = event => {
|
|
212
|
+
if (newNote()) {
|
|
213
|
+
setNewNoteIndex(-1);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (!event.altKey) return;
|
|
217
|
+
insertOrUpdateNote(event);
|
|
218
|
+
};
|
|
219
|
+
_el$.$$dblclick = event => {
|
|
220
|
+
insertOrUpdateNote(event);
|
|
221
|
+
};
|
|
222
|
+
_el$.$$mouseup = event => {
|
|
223
|
+
setIsMouseDown(false);
|
|
224
|
+
if (!event.altKey) return;
|
|
225
|
+
insertOrUpdateNote(event);
|
|
226
|
+
};
|
|
227
|
+
_el$.$$mousemove = event => {
|
|
228
|
+
if (isDragging()) return;
|
|
229
|
+
if (!isMouseDown()) {
|
|
230
|
+
setNoteDragMode(undefined);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const index = insertOrUpdateNote(event);
|
|
234
|
+
console.log({
|
|
235
|
+
index
|
|
236
|
+
});
|
|
237
|
+
setNewNoteIndex(index);
|
|
238
|
+
};
|
|
239
|
+
_el$.$$mousedown = () => {
|
|
240
|
+
console.log("down");
|
|
241
|
+
setIsMouseDown(true);
|
|
242
|
+
};
|
|
245
243
|
const _ref$ = props.ref;
|
|
246
|
-
typeof _ref$ === "function" ? use(_ref$, _el$
|
|
247
|
-
_el
|
|
248
|
-
_el$2.style.setProperty("height", "100%");
|
|
249
|
-
insert(_el$2, createComponent(Index, {
|
|
244
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
|
|
245
|
+
insert(_el$, createComponent(Index, {
|
|
250
246
|
get each() {
|
|
251
247
|
return context.notes;
|
|
252
248
|
},
|
|
253
249
|
children: (note, index) => {
|
|
254
|
-
const
|
|
255
|
-
const
|
|
250
|
+
const verticalVirtualDimensionss = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
|
|
251
|
+
const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
|
|
256
252
|
return createComponent(Show, {
|
|
257
253
|
get when() {
|
|
258
|
-
return memo(() => !!!!
|
|
254
|
+
return memo(() => !!!!verticalVirtualDimensionss().size)() && !!horizontalDimensions().size;
|
|
259
255
|
},
|
|
260
256
|
get children() {
|
|
261
|
-
const _el$
|
|
262
|
-
_el$
|
|
263
|
-
|
|
264
|
-
|
|
257
|
+
const _el$2 = _tmpl$$5.cloneNode(true);
|
|
258
|
+
_el$2.$$mousedown = event => {
|
|
259
|
+
event.stopPropagation();
|
|
260
|
+
setIsDragging(true);
|
|
261
|
+
const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
|
|
265
262
|
const diffPosition = initialPosition - note().ticks;
|
|
266
263
|
const handleMouseMove = mouseMoveEvent => {
|
|
267
|
-
const ticks = snapValueToGridIfEnabled(Math.max(
|
|
264
|
+
const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
|
|
268
265
|
context.onNoteChange?.(index, {
|
|
269
266
|
...note(),
|
|
270
|
-
...(
|
|
271
|
-
midi: Math.round(127 -
|
|
267
|
+
...(noteDragMode() === "move" && {
|
|
268
|
+
midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
|
|
272
269
|
}),
|
|
273
|
-
...((
|
|
270
|
+
...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
|
|
274
271
|
ticks
|
|
275
272
|
}),
|
|
276
|
-
...(
|
|
273
|
+
...(noteDragMode() === "trimStart" && {
|
|
277
274
|
durationTicks: note().durationTicks + note().ticks - ticks
|
|
278
275
|
}),
|
|
279
|
-
...(
|
|
280
|
-
durationTicks: snapValueToGridIfEnabled(
|
|
276
|
+
...(noteDragMode() === "trimEnd" && {
|
|
277
|
+
durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note().ticks, mouseMoveEvent.altKey)
|
|
281
278
|
})
|
|
282
279
|
});
|
|
283
280
|
};
|
|
284
281
|
const handleMouseUp = () => {
|
|
285
|
-
|
|
282
|
+
setIsDragging(false);
|
|
286
283
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
287
284
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
288
285
|
};
|
|
289
286
|
window.addEventListener("mousemove", handleMouseMove);
|
|
290
287
|
window.addEventListener("mouseup", handleMouseUp);
|
|
291
288
|
};
|
|
292
|
-
_el$
|
|
289
|
+
_el$2.$$dblclick = event => {
|
|
290
|
+
event.stopPropagation();
|
|
293
291
|
context.onRemoveNote?.(index);
|
|
294
292
|
};
|
|
295
|
-
_el$
|
|
296
|
-
if (
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
const
|
|
300
|
-
|
|
293
|
+
_el$2.$$mousemove = event => {
|
|
294
|
+
if (isDragging()) return;
|
|
295
|
+
event.stopPropagation();
|
|
296
|
+
const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
|
|
297
|
+
const noteStartX = horizontalViewPort().calculatePixelValue(note().ticks);
|
|
298
|
+
const noteEndX = horizontalViewPort().calculatePixelValue(note().ticks + note().durationTicks);
|
|
299
|
+
setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
|
|
301
300
|
};
|
|
302
|
-
_el$3.style.setProperty("z-index", "2");
|
|
303
|
-
_el$3.style.setProperty("position", "absolute");
|
|
304
|
-
_el$3.style.setProperty("box-sizing", "border-box");
|
|
305
|
-
_el$3.style.setProperty("border-width", "0.5px");
|
|
306
|
-
_el$3.style.setProperty("border-style", "solid");
|
|
307
|
-
_el$3.style.setProperty("border-color", "#a00");
|
|
308
301
|
effect(_p$ => {
|
|
309
|
-
const _v$
|
|
310
|
-
_v$
|
|
311
|
-
_v$
|
|
312
|
-
_v$
|
|
313
|
-
_v$
|
|
314
|
-
|
|
315
|
-
_v$
|
|
316
|
-
_v$
|
|
317
|
-
_v$
|
|
318
|
-
_v$
|
|
302
|
+
const _v$ = getClasses(noteDragMode()).join(" "),
|
|
303
|
+
_v$2 = `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
|
|
304
|
+
_v$3 = `${verticalVirtualDimensionss().offset}px`,
|
|
305
|
+
_v$4 = `${verticalVirtualDimensionss().size}px`,
|
|
306
|
+
_v$5 = `${horizontalDimensions().offset}px`,
|
|
307
|
+
_v$6 = `${horizontalDimensions().size}px`;
|
|
308
|
+
_v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
|
|
309
|
+
_v$2 !== _p$._v$2 && _el$2.style.setProperty("background-color", _p$._v$2 = _v$2);
|
|
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);
|
|
319
314
|
return _p$;
|
|
320
315
|
}, {
|
|
316
|
+
_v$: undefined,
|
|
317
|
+
_v$2: undefined,
|
|
318
|
+
_v$3: undefined,
|
|
321
319
|
_v$4: undefined,
|
|
322
320
|
_v$5: undefined,
|
|
323
|
-
_v$6: undefined
|
|
324
|
-
_v$7: undefined,
|
|
325
|
-
_v$8: undefined
|
|
321
|
+
_v$6: undefined
|
|
326
322
|
});
|
|
327
|
-
return _el$
|
|
323
|
+
return _el$2;
|
|
328
324
|
}
|
|
329
325
|
});
|
|
330
326
|
}
|
|
331
327
|
}));
|
|
332
|
-
effect(
|
|
333
|
-
const _v$ = `${context.clientRect.width}px`,
|
|
334
|
-
_v$2 = `${context.clientRect.height}px`,
|
|
335
|
-
_v$3 = `${context.clientRect.width}px`;
|
|
336
|
-
_v$ !== _p$._v$ && _el$.style.setProperty("width", _p$._v$ = _v$);
|
|
337
|
-
_v$2 !== _p$._v$2 && _el$.style.setProperty("height", _p$._v$2 = _v$2);
|
|
338
|
-
_v$3 !== _p$._v$3 && _el$2.style.setProperty("width", _p$._v$3 = _v$3);
|
|
339
|
-
return _p$;
|
|
340
|
-
}, {
|
|
341
|
-
_v$: undefined,
|
|
342
|
-
_v$2: undefined,
|
|
343
|
-
_v$3: undefined
|
|
344
|
-
});
|
|
328
|
+
effect(() => className(_el$, styles$1.PianoRollNotes));
|
|
345
329
|
return _el$;
|
|
346
330
|
})();
|
|
347
331
|
};
|
|
348
|
-
delegateEvents(["mousemove", "dblclick", "
|
|
332
|
+
delegateEvents(["mousedown", "mousemove", "mouseup", "dblclick", "click"]);
|
|
349
333
|
|
|
350
|
-
const _tmpl$$
|
|
334
|
+
const _tmpl$$4 = /*#__PURE__*/template(`<div class="PianoRoll-Scroller"><div><div><div></div></div></div></div>`, 8);
|
|
351
335
|
const ScrollContainer = props => {
|
|
352
336
|
let scrollContentRef;
|
|
353
|
-
const
|
|
354
|
-
const
|
|
355
|
-
const forwardEventToNote = event => {
|
|
356
|
-
const x = "clientX" in event ? event.clientX : event.touches[0]?.clientX ?? 0;
|
|
357
|
-
const y = "clientY" in event ? event.clientY : event.touches[0]?.clientY ?? 0;
|
|
358
|
-
const elementUnderMouse = [...(context.notesContainer?.querySelectorAll?.("div") ?? [])].find(element => {
|
|
359
|
-
const rect = element.getBoundingClientRect();
|
|
360
|
-
return x >= rect.left && rect.left + rect.width > x && y >= rect.top && rect.top + rect.height > y;
|
|
361
|
-
});
|
|
362
|
-
if (elementUnderMouse) {
|
|
363
|
-
return elementUnderMouse.dispatchEvent(new MouseEvent(event.type, event));
|
|
364
|
-
}
|
|
365
|
-
};
|
|
337
|
+
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
338
|
+
const horizontalViewPort = createMemo(() => useViewPortDimension("horizontal"));
|
|
366
339
|
const handleScroll = event => {
|
|
367
340
|
event.preventDefault();
|
|
368
341
|
if (didUpdateScroll) {
|
|
369
342
|
didUpdateScroll = false;
|
|
370
343
|
return;
|
|
371
344
|
}
|
|
372
|
-
const maxVerticalPosition =
|
|
373
|
-
const maxPosition =
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
height
|
|
377
|
-
} = context.clientRect;
|
|
345
|
+
const maxVerticalPosition = verticalViewPort().calculateMaxPosition();
|
|
346
|
+
const maxPosition = horizontalViewPort().calculateMaxPosition();
|
|
347
|
+
const height = verticalViewPort().pixelSize;
|
|
348
|
+
const width = horizontalViewPort().pixelSize;
|
|
378
349
|
const {
|
|
379
350
|
scrollTop,
|
|
380
351
|
scrollLeft,
|
|
@@ -383,23 +354,35 @@ const ScrollContainer = props => {
|
|
|
383
354
|
} = event.currentTarget;
|
|
384
355
|
const scrollTopAmount = scrollTop / (scrollHeight - height);
|
|
385
356
|
const scrollLeftAmount = scrollLeft / (scrollWidth - width);
|
|
386
|
-
|
|
387
|
-
|
|
357
|
+
verticalViewPort().onPositionChange?.(maxVerticalPosition * scrollTopAmount);
|
|
358
|
+
horizontalViewPort().onPositionChange?.(maxPosition * scrollLeftAmount);
|
|
359
|
+
};
|
|
360
|
+
const handleWheel = event => {
|
|
361
|
+
if (event.altKey) {
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
if (Math.abs(event.deltaX) > Math.abs(event.deltaY)) {
|
|
364
|
+
horizontalViewPort()?.onZoomChange?.(horizontalViewPort().zoom * (1 + event.deltaX / horizontalViewPort().pixelSize));
|
|
365
|
+
const maxPosition = horizontalViewPort().calculateMaxPosition();
|
|
366
|
+
horizontalViewPort()?.onPositionChange?.(Math.min(maxPosition, horizontalViewPort()?.position));
|
|
367
|
+
} else {
|
|
368
|
+
verticalViewPort()?.onZoomChange?.(verticalViewPort().zoom * (1 + event.deltaY / verticalViewPort().pixelSize));
|
|
369
|
+
const maxVerticalPosition = verticalViewPort().calculateMaxPosition();
|
|
370
|
+
verticalViewPort()?.onPositionChange?.(Math.min(maxVerticalPosition, verticalViewPort()?.position));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
388
373
|
};
|
|
389
374
|
let didUpdateScroll = false;
|
|
390
375
|
createEffect(() => {
|
|
391
|
-
const maxVerticalPosition =
|
|
392
|
-
const maxPosition =
|
|
393
|
-
const scrollTopAmount = maxVerticalPosition > 0 ?
|
|
394
|
-
const scrollLeftAmount = maxPosition > 0 ?
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
width
|
|
398
|
-
} = context.clientRect;
|
|
376
|
+
const maxVerticalPosition = verticalViewPort().calculateMaxPosition();
|
|
377
|
+
const maxPosition = horizontalViewPort().calculateMaxPosition();
|
|
378
|
+
const scrollTopAmount = maxVerticalPosition > 0 ? verticalViewPort().position / maxVerticalPosition : 0;
|
|
379
|
+
const scrollLeftAmount = maxPosition > 0 ? horizontalViewPort().position / maxPosition : 0;
|
|
380
|
+
const height = verticalViewPort().pixelSize;
|
|
381
|
+
const width = horizontalViewPort().pixelSize;
|
|
399
382
|
if (!scrollContentRef?.parentElement) return;
|
|
400
|
-
const scrollDivHeight =
|
|
383
|
+
const scrollDivHeight = verticalViewPort().zoom * verticalViewPort().pixelSize;
|
|
401
384
|
const scrollTop = scrollTopAmount * (scrollDivHeight - height);
|
|
402
|
-
const scrollDivWidth =
|
|
385
|
+
const scrollDivWidth = horizontalViewPort().zoom * horizontalViewPort().pixelSize;
|
|
403
386
|
const scrollLeft = scrollLeftAmount * (scrollDivWidth - width);
|
|
404
387
|
didUpdateScroll = true;
|
|
405
388
|
scrollContentRef.style.height = `${scrollDivHeight}px`;
|
|
@@ -409,143 +392,71 @@ const ScrollContainer = props => {
|
|
|
409
392
|
top: scrollTop
|
|
410
393
|
});
|
|
411
394
|
});
|
|
412
|
-
const insertOrUpdateNote = event => {
|
|
413
|
-
const position = context.horizontalViewPort.getPosition(event.clientX);
|
|
414
|
-
const midi = 127 - Math.floor(context.verticalViewPort.getPosition(event.clientY));
|
|
415
|
-
const eventPositionTicks = Math.floor(position / gridDivisorTicks()) * gridDivisorTicks();
|
|
416
|
-
const velocity = 127;
|
|
417
|
-
const existingNote = newNote();
|
|
418
|
-
const ticks = existingNote?.ticks ?? eventPositionTicks;
|
|
419
|
-
const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisorTicks();
|
|
420
|
-
const note = {
|
|
421
|
-
midi,
|
|
422
|
-
ticks,
|
|
423
|
-
durationTicks,
|
|
424
|
-
velocity
|
|
425
|
-
};
|
|
426
|
-
if (existingNote) {
|
|
427
|
-
context.onNoteChange?.(newNoteIndex(), note);
|
|
428
|
-
return newNoteIndex();
|
|
429
|
-
} else {
|
|
430
|
-
return context.onInsertNote?.(note) ?? -1;
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
const [newNoteIndex, setNewNoteIndex] = createSignal(-1);
|
|
434
|
-
const newNote = createMemo(() => context.notes[newNoteIndex()]);
|
|
435
|
-
const [isMouseDown, setIsMouseDown] = createSignal(false);
|
|
436
395
|
return (() => {
|
|
437
|
-
const _el$ = _tmpl$$
|
|
438
|
-
_el$2 = _el$.firstChild
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
_el$.addEventListener("
|
|
442
|
-
_el$.addEventListener("touchcancel", forwardEventToNote);
|
|
443
|
-
_el$.$$touchend = forwardEventToNote;
|
|
444
|
-
_el$.$$touchmove = forwardEventToNote;
|
|
445
|
-
_el$.$$touchstart = forwardEventToNote;
|
|
446
|
-
_el$.$$mouseup = event => {
|
|
447
|
-
setIsMouseDown(false);
|
|
448
|
-
if (newNote()) return;
|
|
449
|
-
if (forwardEventToNote(event)) return;
|
|
450
|
-
if (!event.altKey) return;
|
|
451
|
-
insertOrUpdateNote(event);
|
|
452
|
-
};
|
|
453
|
-
_el$.$$click = event => {
|
|
454
|
-
if (newNote()) {
|
|
455
|
-
setNewNoteIndex(-1);
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
if (forwardEventToNote(event)) return;
|
|
459
|
-
if (!event.altKey) return;
|
|
460
|
-
insertOrUpdateNote(event);
|
|
461
|
-
};
|
|
462
|
-
_el$.$$dblclick = event => {
|
|
463
|
-
if (newNote()) return;
|
|
464
|
-
if (context.isDragging) return;
|
|
465
|
-
if (forwardEventToNote(event)) return;
|
|
466
|
-
insertOrUpdateNote(event);
|
|
467
|
-
};
|
|
468
|
-
_el$.$$mousemove = event => {
|
|
469
|
-
event.preventDefault();
|
|
470
|
-
if (forwardEventToNote(event)) return;
|
|
471
|
-
if (context.isDragging) return;
|
|
472
|
-
if (!isMouseDown()) {
|
|
473
|
-
context.onNoteDragModeChange(undefined);
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
const index = insertOrUpdateNote(event);
|
|
477
|
-
setNewNoteIndex(index);
|
|
478
|
-
};
|
|
479
|
-
_el$.$$mousedown = event => {
|
|
480
|
-
if (forwardEventToNote(event)) return;
|
|
481
|
-
setIsMouseDown(true);
|
|
482
|
-
};
|
|
396
|
+
const _el$ = _tmpl$$4.cloneNode(true),
|
|
397
|
+
_el$2 = _el$.firstChild,
|
|
398
|
+
_el$3 = _el$2.firstChild,
|
|
399
|
+
_el$4 = _el$3.firstChild;
|
|
400
|
+
_el$.addEventListener("wheel", handleWheel);
|
|
483
401
|
_el$.addEventListener("scroll", handleScroll);
|
|
484
402
|
const _ref$ = props.ref;
|
|
485
403
|
typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
|
|
404
|
+
_el$.style.setProperty("height", "100%");
|
|
405
|
+
_el$.style.setProperty("width", "100%");
|
|
406
|
+
_el$.style.setProperty("z-index", "4");
|
|
407
|
+
_el$.style.setProperty("overflow", "scroll");
|
|
408
|
+
_el$.style.setProperty("pointer-events", "auto");
|
|
486
409
|
const _ref$2 = scrollContentRef;
|
|
487
410
|
typeof _ref$2 === "function" ? use(_ref$2, _el$2) : scrollContentRef = _el$2;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const context = usePianoRollContext();
|
|
505
|
-
return (() => {
|
|
506
|
-
const _el$ = _tmpl$$2.cloneNode(true);
|
|
507
|
-
_el$.$$input = event => context.onVerticalZoomChange?.(event.currentTarget.valueAsNumber);
|
|
508
|
-
spread(_el$, mergeProps({
|
|
509
|
-
get value() {
|
|
510
|
-
return context.verticalZoom;
|
|
511
|
-
}
|
|
512
|
-
}, {
|
|
513
|
-
orient: "vertical"
|
|
411
|
+
_el$3.style.setProperty("top", "0");
|
|
412
|
+
_el$3.style.setProperty("left", "0");
|
|
413
|
+
_el$3.style.setProperty("position", "sticky");
|
|
414
|
+
_el$3.style.setProperty("display", "flex");
|
|
415
|
+
_el$4.style.setProperty("position", "relative");
|
|
416
|
+
insert(_el$4, () => props.children);
|
|
417
|
+
effect(_p$ => {
|
|
418
|
+
const _v$ = `${verticalViewPort().pixelSize}px`,
|
|
419
|
+
_v$2 = `${horizontalViewPort().pixelSize}px`,
|
|
420
|
+
_v$3 = `${verticalViewPort().pixelSize}px`,
|
|
421
|
+
_v$4 = `${horizontalViewPort().pixelSize}px`;
|
|
422
|
+
_v$ !== _p$._v$ && _el$3.style.setProperty("height", _p$._v$ = _v$);
|
|
423
|
+
_v$2 !== _p$._v$2 && _el$3.style.setProperty("width", _p$._v$2 = _v$2);
|
|
424
|
+
_v$3 !== _p$._v$3 && _el$4.style.setProperty("height", _p$._v$3 = _v$3);
|
|
425
|
+
_v$4 !== _p$._v$4 && _el$4.style.setProperty("width", _p$._v$4 = _v$4);
|
|
426
|
+
return _p$;
|
|
514
427
|
}, {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
"-webkit-appearance": "slider-vertical" /* WebKit */
|
|
521
|
-
}
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
}), false, false);
|
|
428
|
+
_v$: undefined,
|
|
429
|
+
_v$2: undefined,
|
|
430
|
+
_v$3: undefined,
|
|
431
|
+
_v$4: undefined
|
|
432
|
+
});
|
|
525
433
|
return _el$;
|
|
526
434
|
})();
|
|
527
435
|
};
|
|
528
|
-
delegateEvents(["input"]);
|
|
529
436
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
437
|
+
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
|
+
var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
|
|
439
|
+
styleInject(css_248z);
|
|
440
|
+
|
|
441
|
+
const _tmpl$$3 = /*#__PURE__*/template(`<div></div>`, 2);
|
|
533
442
|
const PianoRollGrid = () => {
|
|
534
443
|
const context = usePianoRollContext();
|
|
444
|
+
const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
|
|
445
|
+
const horizontalViewPort = createMemo(() => useViewPortDimension("horizontal"));
|
|
535
446
|
const measureTicks = createMemo(() => context.ppq * 4);
|
|
536
447
|
const selectedGridDivisorTicks = createMemo(() => measureTicks() / context.gridDivision);
|
|
537
448
|
function calculateVisibleGridDivisorTicks(value) {
|
|
538
|
-
if (
|
|
449
|
+
if (horizontalViewPort().calculateVisibleRange() / value > 100) {
|
|
539
450
|
return calculateVisibleGridDivisorTicks(value * 2);
|
|
540
451
|
}
|
|
541
|
-
if (
|
|
452
|
+
if (horizontalViewPort().calculateVisibleRange() / value < 30) {
|
|
542
453
|
return calculateVisibleGridDivisorTicks(value / 2);
|
|
543
454
|
}
|
|
544
455
|
return value;
|
|
545
456
|
}
|
|
546
457
|
const gridDivisorTicks = createMemo(() => calculateVisibleGridDivisorTicks(selectedGridDivisorTicks()));
|
|
547
458
|
const gridArray = createMemo(() => {
|
|
548
|
-
const numberOfLines = Math.ceil(
|
|
459
|
+
const numberOfLines = Math.ceil(horizontalViewPort().calculateVisibleRange() / gridDivisorTicks() + 1);
|
|
549
460
|
const startIndex = Math.floor(context.position / gridDivisorTicks());
|
|
550
461
|
return Array.from({
|
|
551
462
|
length: numberOfLines
|
|
@@ -555,148 +466,235 @@ const PianoRollGrid = () => {
|
|
|
555
466
|
}));
|
|
556
467
|
});
|
|
557
468
|
return (() => {
|
|
558
|
-
const _el$ = _tmpl$$
|
|
559
|
-
|
|
560
|
-
_el$.style.setProperty("position", "absolute");
|
|
561
|
-
_el$2.style.setProperty("position", "relative");
|
|
562
|
-
_el$2.style.setProperty("height", "100%");
|
|
563
|
-
insert(_el$2, createComponent(Index, {
|
|
469
|
+
const _el$ = _tmpl$$3.cloneNode(true);
|
|
470
|
+
insert(_el$, createComponent(Index, {
|
|
564
471
|
get each() {
|
|
565
472
|
return gridArray();
|
|
566
473
|
},
|
|
567
474
|
children: entry => {
|
|
568
|
-
const virtualDimensions = createMemo(() =>
|
|
475
|
+
const virtualDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(entry().ticks, gridDivisorTicks()));
|
|
569
476
|
return createComponent(Show, {
|
|
570
477
|
get when() {
|
|
571
478
|
return virtualDimensions().size > 0;
|
|
572
479
|
},
|
|
573
480
|
get children() {
|
|
574
|
-
const _el$
|
|
575
|
-
_el$3.style.setProperty("z-index", "1");
|
|
576
|
-
_el$3.style.setProperty("position", "absolute");
|
|
577
|
-
_el$3.style.setProperty("box-sizing", "border-box");
|
|
578
|
-
_el$3.style.setProperty("top", "0px");
|
|
579
|
-
_el$3.style.setProperty("height", "100%");
|
|
580
|
-
_el$3.style.setProperty("border-left-style", "solid");
|
|
581
|
-
_el$3.style.setProperty("border-left-width", "0.5px");
|
|
481
|
+
const _el$2 = _tmpl$$3.cloneNode(true);
|
|
582
482
|
effect(_p$ => {
|
|
583
|
-
const _v$
|
|
584
|
-
_v$
|
|
585
|
-
_v$
|
|
586
|
-
_v$
|
|
587
|
-
|
|
588
|
-
_v$
|
|
589
|
-
_v$
|
|
590
|
-
_v$
|
|
483
|
+
const _v$ = styles["PianoRollGrid-Time"],
|
|
484
|
+
_v$2 = Math.ceil((entry().index + 1 * selectedGridDivisorTicks()) / measureTicks()) % 2 === 0 ? "#ddd" : "#ccc",
|
|
485
|
+
_v$3 = `${virtualDimensions().offset}px`,
|
|
486
|
+
_v$4 = `${virtualDimensions().size}px`,
|
|
487
|
+
_v$5 = entry().index * gridDivisorTicks() % selectedGridDivisorTicks() === 0 ? "gray" : "#bbb";
|
|
488
|
+
_v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
|
|
489
|
+
_v$2 !== _p$._v$2 && _el$2.style.setProperty("background", _p$._v$2 = _v$2);
|
|
490
|
+
_v$3 !== _p$._v$3 && _el$2.style.setProperty("left", _p$._v$3 = _v$3);
|
|
491
|
+
_v$4 !== _p$._v$4 && _el$2.style.setProperty("width", _p$._v$4 = _v$4);
|
|
492
|
+
_v$5 !== _p$._v$5 && _el$2.style.setProperty("border-left-color", _p$._v$5 = _v$5);
|
|
591
493
|
return _p$;
|
|
592
494
|
}, {
|
|
495
|
+
_v$: undefined,
|
|
496
|
+
_v$2: undefined,
|
|
497
|
+
_v$3: undefined,
|
|
593
498
|
_v$4: undefined,
|
|
594
|
-
_v$5: undefined
|
|
595
|
-
_v$6: undefined,
|
|
596
|
-
_v$7: undefined
|
|
499
|
+
_v$5: undefined
|
|
597
500
|
});
|
|
598
|
-
return _el$
|
|
501
|
+
return _el$2;
|
|
599
502
|
}
|
|
600
503
|
});
|
|
601
504
|
}
|
|
602
505
|
}), null);
|
|
603
|
-
insert(_el
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
506
|
+
insert(_el$, createComponent(Show, {
|
|
507
|
+
get when() {
|
|
508
|
+
return !context.condensed;
|
|
509
|
+
},
|
|
510
|
+
get children() {
|
|
511
|
+
return createComponent(Index, {
|
|
512
|
+
each: keys,
|
|
513
|
+
children: key => {
|
|
514
|
+
const virtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - key().number, 1));
|
|
515
|
+
return createComponent(Show, {
|
|
516
|
+
get when() {
|
|
517
|
+
return virtualDimensions().size > 0;
|
|
518
|
+
},
|
|
519
|
+
get children() {
|
|
520
|
+
const _el$3 = _tmpl$$3.cloneNode(true);
|
|
521
|
+
_el$3.style.setProperty("width", "100%");
|
|
522
|
+
effect(_p$ => {
|
|
523
|
+
const _v$6 = styles["PianoRollGrid-Key"],
|
|
524
|
+
_v$7 = `${virtualDimensions().offset}px`,
|
|
525
|
+
_v$8 = `${virtualDimensions().size}px`,
|
|
526
|
+
_v$9 = key().isBlack ? "rgba(0,0,0,0.2)" : "none",
|
|
527
|
+
_v$10 = `${!key().isBlack && !blackKeys.includes((key().number + 1) % 12) ? "0.1px" : 0} 1px ${!key().isBlack && !blackKeys.includes((key().number - 1) % 12) ? "0.1px" : 0} 0`;
|
|
528
|
+
_v$6 !== _p$._v$6 && className(_el$3, _p$._v$6 = _v$6);
|
|
529
|
+
_v$7 !== _p$._v$7 && _el$3.style.setProperty("top", _p$._v$7 = _v$7);
|
|
530
|
+
_v$8 !== _p$._v$8 && _el$3.style.setProperty("height", _p$._v$8 = _v$8);
|
|
531
|
+
_v$9 !== _p$._v$9 && _el$3.style.setProperty("background-color", _p$._v$9 = _v$9);
|
|
532
|
+
_v$10 !== _p$._v$10 && _el$3.style.setProperty("border-width", _p$._v$10 = _v$10);
|
|
533
|
+
return _p$;
|
|
534
|
+
}, {
|
|
535
|
+
_v$6: undefined,
|
|
536
|
+
_v$7: undefined,
|
|
537
|
+
_v$8: undefined,
|
|
538
|
+
_v$9: undefined,
|
|
539
|
+
_v$10: undefined
|
|
540
|
+
});
|
|
541
|
+
return _el$3;
|
|
542
|
+
}
|
|
633
543
|
});
|
|
634
|
-
return _el$4;
|
|
635
544
|
}
|
|
636
545
|
});
|
|
637
546
|
}
|
|
638
547
|
}), null);
|
|
639
|
-
effect(
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
548
|
+
effect(() => className(_el$, styles.PianoRollGrid));
|
|
549
|
+
return _el$;
|
|
550
|
+
})();
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
const defaultRect = {
|
|
554
|
+
left: 0,
|
|
555
|
+
width: 0,
|
|
556
|
+
top: 0,
|
|
557
|
+
height: 0,
|
|
558
|
+
bottom: 0,
|
|
559
|
+
right: 0,
|
|
560
|
+
x: 0,
|
|
561
|
+
y: 0
|
|
562
|
+
};
|
|
563
|
+
function useBoundingClientRect(containerRef) {
|
|
564
|
+
const [boundingClientRect, setBoundingClientRect] = createSignal(defaultRect);
|
|
565
|
+
createEffect(() => {
|
|
566
|
+
const container = containerRef();
|
|
567
|
+
if (!container) return;
|
|
568
|
+
const updateBoundingClientRect = () => {
|
|
569
|
+
setBoundingClientRect(container.getBoundingClientRect() ?? defaultRect);
|
|
570
|
+
};
|
|
571
|
+
const resizeObserver = new ResizeObserver(updateBoundingClientRect);
|
|
572
|
+
resizeObserver.observe(container);
|
|
573
|
+
updateBoundingClientRect();
|
|
574
|
+
return () => {
|
|
575
|
+
resizeObserver.disconnect();
|
|
576
|
+
};
|
|
577
|
+
});
|
|
578
|
+
return boundingClientRect;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const _tmpl$$2 = /*#__PURE__*/template(`<input min="1" max="11" step="0.01">`, 1);
|
|
582
|
+
const VerticalZoomControl = props => {
|
|
583
|
+
const context = usePianoRollContext();
|
|
584
|
+
return (() => {
|
|
585
|
+
const _el$ = _tmpl$$2.cloneNode(true);
|
|
586
|
+
spread(_el$, mergeProps(props, {
|
|
587
|
+
get value() {
|
|
588
|
+
return context.verticalZoom;
|
|
589
|
+
},
|
|
590
|
+
"onInput": event => context.onVerticalZoomChange?.(event.currentTarget.valueAsNumber),
|
|
591
|
+
"type": "range"
|
|
647
592
|
}, {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
593
|
+
orient: "vertical"
|
|
594
|
+
}, {
|
|
595
|
+
get style() {
|
|
596
|
+
return {
|
|
597
|
+
width: "16px",
|
|
598
|
+
...{
|
|
599
|
+
"writing-mode": "bt-lr" /* IE */,
|
|
600
|
+
"-webkit-appearance": "slider-vertical" /* WebKit */
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
}), false, false);
|
|
652
605
|
return _el$;
|
|
653
606
|
})();
|
|
654
607
|
};
|
|
655
608
|
|
|
656
|
-
const _tmpl
|
|
609
|
+
const _tmpl$$1 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
|
|
610
|
+
const HorizontalZoomControl = props => {
|
|
611
|
+
const context = usePianoRollContext();
|
|
612
|
+
return (() => {
|
|
613
|
+
const _el$ = _tmpl$$1.cloneNode(true);
|
|
614
|
+
spread(_el$, mergeProps(props, {
|
|
615
|
+
get value() {
|
|
616
|
+
return context.zoom;
|
|
617
|
+
},
|
|
618
|
+
"onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
|
|
619
|
+
"type": "range",
|
|
620
|
+
"style": {
|
|
621
|
+
"margin-left": "50px",
|
|
622
|
+
"margin-right": "16px"
|
|
623
|
+
}
|
|
624
|
+
}), false, false);
|
|
625
|
+
return _el$;
|
|
626
|
+
})();
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const _tmpl$ = /*#__PURE__*/template(`<div><div></div></div>`, 4);
|
|
657
630
|
const PianoRoll = allProps => {
|
|
658
|
-
const [contextProps, divProps] = splitProps(allProps, ["
|
|
659
|
-
const [
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
631
|
+
const [contextProps, divProps] = splitProps(allProps, ["ppq", "notes", "position", "duration", "zoom", "verticalPosition", "verticalZoom", "onVerticalZoomChange", "onVerticalPositionChange", "onZoomChange", "onPositionChange", "onNoteChange", "gridDivision", "snapToGrid", "onInsertNote", "onRemoveNote"]);
|
|
632
|
+
const [scrollerRef, setScrollerRef] = createSignal();
|
|
633
|
+
const clientRect = useBoundingClientRect(scrollerRef);
|
|
634
|
+
const zoomFactor = 500;
|
|
635
|
+
const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
|
|
636
|
+
const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
|
|
637
|
+
const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
|
|
638
|
+
const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
|
|
639
|
+
return createComponent(PianoRollContextProvider, {
|
|
640
|
+
value: contextProps,
|
|
668
641
|
get children() {
|
|
669
642
|
const _el$ = _tmpl$.cloneNode(true),
|
|
670
|
-
_el$2 = _el$.firstChild
|
|
671
|
-
_el$3 = _el$2.firstChild;
|
|
643
|
+
_el$2 = _el$.firstChild;
|
|
672
644
|
spread(_el$, mergeProps(divProps, {
|
|
673
645
|
get ["class"]() {
|
|
674
|
-
return styles$
|
|
646
|
+
return styles$3.PianoRoll;
|
|
675
647
|
}
|
|
676
648
|
}), false, true);
|
|
677
|
-
insert(_el$2, createComponent(
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
649
|
+
insert(_el$2, createComponent(ScrollZoomViewPort, {
|
|
650
|
+
dimensions: {
|
|
651
|
+
horizontal: () => ({
|
|
652
|
+
pixelOffset: clientRect().left,
|
|
653
|
+
pixelSize: clientRect().width,
|
|
654
|
+
position: contextProps.position,
|
|
655
|
+
range: contextProps.duration,
|
|
656
|
+
zoom: contextProps.zoom * (zoomFactor / clientRect().width),
|
|
657
|
+
onPositionChange: contextProps.onPositionChange,
|
|
658
|
+
onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
|
|
659
|
+
}),
|
|
660
|
+
vertical: () => ({
|
|
661
|
+
pixelOffset: clientRect().top,
|
|
662
|
+
pixelSize: clientRect().height,
|
|
663
|
+
position: contextProps.verticalPosition,
|
|
664
|
+
range: 128,
|
|
665
|
+
zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
|
|
666
|
+
onPositionChange: contextProps.onVerticalPositionChange,
|
|
667
|
+
onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
|
|
668
|
+
})
|
|
669
|
+
},
|
|
670
|
+
get children() {
|
|
671
|
+
return [createComponent(PianoRollKeys, {}), createComponent(ScrollContainer, {
|
|
672
|
+
ref: setScrollerRef,
|
|
673
|
+
get children() {
|
|
674
|
+
return [createComponent(PianoRollGrid, {}), createComponent(PianoRollNotes, {})];
|
|
675
|
+
}
|
|
676
|
+
}), createComponent(VerticalZoomControl, {
|
|
677
|
+
get min() {
|
|
678
|
+
return minVerticalZoom();
|
|
679
|
+
},
|
|
680
|
+
get max() {
|
|
681
|
+
return maxVerticalZoom();
|
|
682
|
+
}
|
|
683
|
+
})];
|
|
684
|
+
}
|
|
685
|
+
}));
|
|
686
|
+
insert(_el$, createComponent(HorizontalZoomControl, {
|
|
687
|
+
get min() {
|
|
688
|
+
return minZoom();
|
|
689
|
+
},
|
|
690
|
+
get max() {
|
|
691
|
+
return maxZoom();
|
|
692
|
+
}
|
|
684
693
|
}), null);
|
|
685
|
-
|
|
686
|
-
insert(_el$, createComponent(HorizontalZoomControl, {}), null);
|
|
687
|
-
effect(_p$ => {
|
|
688
|
-
const _v$ = styles$1.PianoRollContainer,
|
|
689
|
-
_v$2 = styles$1.PianoRollInnerContainer;
|
|
690
|
-
_v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
|
|
691
|
-
_v$2 !== _p$._v$2 && className(_el$3, _p$._v$2 = _v$2);
|
|
692
|
-
return _p$;
|
|
693
|
-
}, {
|
|
694
|
-
_v$: undefined,
|
|
695
|
-
_v$2: undefined
|
|
696
|
-
});
|
|
694
|
+
effect(() => className(_el$2, styles$3.PianoRollContainer));
|
|
697
695
|
return _el$;
|
|
698
696
|
}
|
|
699
|
-
})
|
|
697
|
+
});
|
|
700
698
|
};
|
|
701
699
|
|
|
702
700
|
const usePianoRoll = () => {
|
|
@@ -708,7 +706,7 @@ const usePianoRoll = () => {
|
|
|
708
706
|
const [gridDivision, onGridDivisionChange] = createSignal(16);
|
|
709
707
|
const [snapToGrid, onSnapToGridChange] = createSignal(true);
|
|
710
708
|
const [notes, onNotesChange] = createSignal([]);
|
|
711
|
-
const [duration,
|
|
709
|
+
const [duration, onDurationChange] = createSignal(0);
|
|
712
710
|
const onNoteChange = (index, note) => {
|
|
713
711
|
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
714
712
|
};
|
|
@@ -723,7 +721,10 @@ const usePianoRoll = () => {
|
|
|
723
721
|
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
724
722
|
};
|
|
725
723
|
createEffect(() => {
|
|
726
|
-
|
|
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
|
+
}
|
|
727
728
|
});
|
|
728
729
|
return {
|
|
729
730
|
ppq,
|
|
@@ -745,7 +746,8 @@ const usePianoRoll = () => {
|
|
|
745
746
|
onNoteChange,
|
|
746
747
|
onInsertNote,
|
|
747
748
|
onRemoveNote,
|
|
748
|
-
duration
|
|
749
|
+
duration,
|
|
750
|
+
onDurationChange
|
|
749
751
|
};
|
|
750
752
|
};
|
|
751
753
|
|