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