solid-pianoroll 0.0.14 → 0.0.15

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/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { spread, mergeProps, template, createComponent, delegateEvents, use, insert, memo, effect, className, style, classList, setAttribute } from 'solid-js/web';
2
- import { createContext, splitProps, useContext, createEffect, createMemo, createSignal, Index, Show, mergeProps as mergeProps$1 } from 'solid-js';
1
+ import { createComponent, insert, effect, classList, setAttribute, className, template, delegateEvents, use, memo, spread, mergeProps } from 'solid-js/web';
2
+ import { createContext, splitProps, useContext, createEffect, createMemo, Index, Show, createSignal, batch, For, mergeProps as mergeProps$1 } from 'solid-js';
3
3
  import { createStore } from 'solid-js/store';
4
4
 
5
5
  function styleInject(css, ref) {
@@ -27,9 +27,9 @@ function styleInject(css, ref) {
27
27
  }
28
28
  }
29
29
 
30
- var css_248z$3 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\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);
30
+ var css_248z$4 = ".PianoRoll-module_PianoRoll__rkRYx {\n box-sizing: border-box;\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.PianoRoll-module_PianoRollContainer__Oyxr7 {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: row;\n}\n";
31
+ var styles$4 = {"PianoRoll":"PianoRoll-module_PianoRoll__rkRYx","PianoRollContainer":"PianoRoll-module_PianoRollContainer__Oyxr7"};
32
+ styleInject(css_248z$4);
33
33
 
34
34
  const PianoRollContext = createContext();
35
35
  const PianoRollContextProvider = PianoRollContext.Provider;
@@ -38,30 +38,11 @@ const usePianoRollContext = () => {
38
38
  if (!context) throw new Error("No PianoRollContext found");
39
39
  return context;
40
40
  };
41
- const splitContextProps = allProps => splitProps(allProps, ["condensed", "duration", "gridDivision", "notes", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange"]);
41
+ const splitContextProps = allProps => splitProps(allProps, ["mode", "duration", "gridDivision", "tracks", "position", "ppq", "snapToGrid", "verticalPosition", "verticalZoom", "zoom", "onInsertNote", "onNoteChange", "onPositionChange", "onRemoveNote", "onVerticalPositionChange", "onVerticalZoomChange", "onZoomChange", "showAllTracks", "selectedTrackIndex", "onSelectedTrackIndexChange"]);
42
42
 
43
- const _tmpl$$8 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
44
- const HorizontalZoomControl = props => {
45
- const context = usePianoRollContext();
46
- return (() => {
47
- const _el$ = _tmpl$$8.cloneNode(true);
48
- spread(_el$, mergeProps(props, {
49
- get value() {
50
- return context.zoom;
51
- },
52
- "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
53
- "type": "range",
54
- get style() {
55
- return {
56
- "margin-left": "50px",
57
- "margin-right": "16px",
58
- ...(typeof props.style === "object" && props.style)
59
- };
60
- }
61
- }), false, false);
62
- return _el$;
63
- })();
64
- };
43
+ var css_248z$3 = ".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";
44
+ var styles$3 = {"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"};
45
+ styleInject(css_248z$3);
65
46
 
66
47
  function createViewPortDimension(getState) {
67
48
  const getStateWithFunctions = () => ({
@@ -135,6 +116,65 @@ const useViewPortDimension = name => {
135
116
  return viewPort;
136
117
  };
137
118
 
119
+ const _tmpl$$8 = /*#__PURE__*/template(`<div></div>`, 2);
120
+ const PianoRollKeys = () => {
121
+ const viewPort = createMemo(() => useViewPortDimension("vertical"));
122
+ return (() => {
123
+ const _el$ = _tmpl$$8.cloneNode(true);
124
+ insert(_el$, createComponent(Index, {
125
+ each: keys,
126
+ children: key => {
127
+ const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
128
+ return createComponent(Show, {
129
+ get when() {
130
+ return virtualDimensions().size > 0;
131
+ },
132
+ get children() {
133
+ const _el$2 = _tmpl$$8.cloneNode(true);
134
+ effect(_p$ => {
135
+ const _v$ = {
136
+ [styles$3["Key"]]: true,
137
+ [styles$3["black"]]: key().isBlack,
138
+ [styles$3["white"]]: !key().isBlack,
139
+ [styles$3["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
140
+ [styles$3["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
141
+ },
142
+ _v$2 = key().name,
143
+ _v$3 = key().number % 12,
144
+ _v$4 = `${virtualDimensions().offset}px`,
145
+ _v$5 = `${virtualDimensions().size}px`;
146
+ _p$._v$ = classList(_el$2, _v$, _p$._v$);
147
+ _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
148
+ _v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
149
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
150
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
151
+ return _p$;
152
+ }, {
153
+ _v$: undefined,
154
+ _v$2: undefined,
155
+ _v$3: undefined,
156
+ _v$4: undefined,
157
+ _v$5: undefined
158
+ });
159
+ return _el$2;
160
+ }
161
+ });
162
+ }
163
+ }));
164
+ effect(() => className(_el$, styles$3.PianoRollKeys));
165
+ return _el$;
166
+ })();
167
+ };
168
+ const blackKeys = [1, 3, 6, 8, 10];
169
+ const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
170
+ const keys = Array.from({
171
+ length: 128
172
+ }).map((_, index) => ({
173
+ number: index,
174
+ name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
175
+ isBlack: blackKeys.includes(index % 12)
176
+ }));
177
+
138
178
  var css_248z$2 = ".PianoRollNotes-module_PianoRollNotes__6pF-y {\n position: absolute;\n flex: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 1;\n cursor: grab;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb {\n position: absolute;\n box-sizing: border-box;\n border-width: 0.5px;\n border-style: solid;\n border-color: #a00;\n cursor: move;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimStart__vuBlj {\n cursor: w-resize;\n}\n.PianoRollNotes-module_PianoRollNotes__6pF-y .PianoRollNotes-module_Note__-jxLb.PianoRollNotes-module_trimEnd__zPdjr {\n cursor: e-resize;\n}";
139
179
  var styles$2 = {"PianoRollNotes":"PianoRollNotes-module_PianoRollNotes__6pF-y","Note":"PianoRollNotes-module_Note__-jxLb","trimStart":"PianoRollNotes-module_trimStart__vuBlj","trimEnd":"PianoRollNotes-module_trimEnd__zPdjr"};
140
180
  styleInject(css_248z$2);
@@ -148,10 +188,11 @@ const PianoRollNotes = props => {
148
188
  const snapValueToGridIfEnabled = (value, altKey) => context.snapToGrid && !altKey ? Math.round(value / gridDivisionTicks()) * gridDivisionTicks() : value;
149
189
  const insertOrUpdateNote = event => {
150
190
  const position = horizontalViewPort().calculatePosition(event.clientX);
151
- const midi = context.condensed ? 60 : 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
191
+ const existingNote = currentNote();
192
+ const midi = context.mode === "keys" ? 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY)) : existingNote?.midi ?? 60;
193
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(event.clientY)) : context.selectedTrackIndex ?? 0;
152
194
  const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
153
195
  const velocity = 127;
154
- const existingNote = newNote();
155
196
  const ticks = existingNote?.ticks ?? eventPositionTicks;
156
197
  const durationTicks = existingNote?.ticks ? eventPositionTicks - existingNote?.ticks : gridDivisionTicks();
157
198
  const note = {
@@ -161,25 +202,26 @@ const PianoRollNotes = props => {
161
202
  velocity
162
203
  };
163
204
  if (existingNote) {
164
- context.onNoteChange?.(newNoteIndex(), note);
165
- return newNoteIndex();
205
+ context.onNoteChange?.(currentNoteTrackIndex(), currentNoteIndex(), note);
206
+ return currentNoteIndex();
166
207
  } else {
167
- return context.onInsertNote?.(note) ?? -1;
208
+ return context.onInsertNote?.(targetTrackIndex, note) ?? -1;
168
209
  }
169
210
  };
170
211
  const [isDragging, setIsDragging] = createSignal(false);
171
212
  const [noteDragMode, setNoteDragMode] = createSignal();
172
- const [newNoteIndex, setNewNoteIndex] = createSignal(-1);
213
+ const [currentNoteIndex, setCurrentNoteIndex] = createSignal(-1);
214
+ const [currentNoteTrackIndex, setCurrentNoteTrackIndex] = createSignal(-1);
173
215
  const [isMouseDown, setIsMouseDown] = createSignal(false);
174
- const newNote = createMemo(() => context.notes[newNoteIndex()]);
216
+ const currentNote = createMemo(() => context.tracks[currentNoteTrackIndex()]?.notes[currentNoteIndex()]);
175
217
  const getClasses = noteDragMode => {
176
218
  return noteDragMode ? [styles$2.Note, styles$2[noteDragMode]] : [styles$2.Note];
177
219
  };
178
220
  return (() => {
179
221
  const _el$ = _tmpl$$7.cloneNode(true);
180
222
  _el$.$$click = event => {
181
- if (newNote()) {
182
- setNewNoteIndex(-1);
223
+ if (currentNote()) {
224
+ setCurrentNoteIndex(-1);
183
225
  return;
184
226
  }
185
227
  if (!event.altKey) return;
@@ -200,94 +242,133 @@ const PianoRollNotes = props => {
200
242
  return;
201
243
  }
202
244
  const index = insertOrUpdateNote(event);
203
- setNewNoteIndex(index);
245
+ setCurrentNoteIndex(index);
204
246
  };
205
247
  _el$.$$mousedown = event => {
206
- console.log("down");
207
- setIsMouseDown(true);
208
- const index = insertOrUpdateNote(event);
209
- setNewNoteIndex(index);
248
+ batch(() => {
249
+ setIsMouseDown(true);
250
+ const index = insertOrUpdateNote(event);
251
+ setCurrentNoteTrackIndex(context.selectedTrackIndex ?? 0);
252
+ setCurrentNoteIndex(index);
253
+ });
210
254
  };
211
255
  const _ref$ = props.ref;
212
256
  typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
213
- insert(_el$, createComponent(Index, {
257
+ insert(_el$, createComponent(For, {
214
258
  get each() {
215
- return context.notes;
259
+ return context.tracks;
216
260
  },
217
- children: (note, index) => {
218
- const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
219
- const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
261
+ children: (track, trackIndex) => {
220
262
  return createComponent(Show, {
221
263
  get when() {
222
- return memo(() => !!(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed))() && horizontalViewPort().isVisible(horizontalDimensions());
264
+ return trackIndex() === context.selectedTrackIndex || context.showAllTracks || context.mode === "tracks";
223
265
  },
224
266
  get children() {
225
- const _el$2 = _tmpl$$7.cloneNode(true);
226
- _el$2.$$mousedown = event => {
227
- event.stopPropagation();
228
- setIsDragging(true);
229
- const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
230
- const diffPosition = initialPosition - note().ticks;
231
- const handleMouseMove = mouseMoveEvent => {
232
- const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
233
- context.onNoteChange?.(index, {
234
- ...note(),
235
- ...(noteDragMode() === "move" && !context.condensed && {
236
- midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
237
- }),
238
- ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
239
- ticks
240
- }),
241
- ...(noteDragMode() === "trimStart" && {
242
- durationTicks: note().durationTicks + note().ticks - ticks
243
- }),
244
- ...(noteDragMode() === "trimEnd" && {
245
- durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note().ticks, mouseMoveEvent.altKey)
246
- })
267
+ return createComponent(For, {
268
+ get each() {
269
+ return track.notes;
270
+ },
271
+ children: (note, noteIndex) => {
272
+ const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(context.mode === "keys" ? 127 - note.midi : trackIndex(), 1));
273
+ const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note.ticks, note.durationTicks));
274
+ return createComponent(Show, {
275
+ get when() {
276
+ return memo(() => !!verticalViewPort().isVisible(verticalVirtualDimensions()))() && horizontalViewPort().isVisible(horizontalDimensions());
277
+ },
278
+ get children() {
279
+ const _el$2 = _tmpl$$7.cloneNode(true);
280
+ _el$2.$$mousedown = event => {
281
+ event.stopPropagation();
282
+ setIsDragging(true);
283
+ setCurrentNoteIndex(noteIndex());
284
+ setCurrentNoteTrackIndex(trackIndex());
285
+ const initialPosition = horizontalViewPort().calculatePosition(event.clientX);
286
+ const diffPosition = initialPosition - note.ticks;
287
+ const handleMouseMove = mouseMoveEvent => {
288
+ const note = currentNote();
289
+ if (!note) return;
290
+ const ticks = snapValueToGridIfEnabled(Math.max(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - diffPosition, 0), mouseMoveEvent.altKey);
291
+ const updatedNote = {
292
+ ...note,
293
+ ...(noteDragMode() === "move" && context.mode === "keys" && {
294
+ midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY))
295
+ }),
296
+ ...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
297
+ ticks
298
+ }),
299
+ ...(noteDragMode() === "trimStart" && {
300
+ durationTicks: note.durationTicks + note.ticks - ticks
301
+ }),
302
+ ...(noteDragMode() === "trimEnd" && {
303
+ durationTicks: snapValueToGridIfEnabled(horizontalViewPort().calculatePosition(mouseMoveEvent.clientX) - note.ticks, mouseMoveEvent.altKey)
304
+ })
305
+ };
306
+ const previousTrackIndex = currentNoteTrackIndex();
307
+ const previousNoteIndex = currentNoteIndex();
308
+ const targetTrackIndex = context.mode === "tracks" ? Math.floor(verticalViewPort().calculatePosition(mouseMoveEvent.clientY)) : previousTrackIndex;
309
+ if (targetTrackIndex === previousTrackIndex) {
310
+ context.onNoteChange?.(previousTrackIndex, previousNoteIndex, updatedNote);
311
+ } else {
312
+ batch(() => {
313
+ if (context.onInsertNote) {
314
+ context.onRemoveNote?.(previousTrackIndex, previousNoteIndex);
315
+ const newNoteIndex = context.onInsertNote(targetTrackIndex, updatedNote);
316
+ setCurrentNoteTrackIndex(targetTrackIndex);
317
+ setCurrentNoteIndex(newNoteIndex);
318
+ }
319
+ });
320
+ }
321
+ };
322
+ const handleMouseUp = () => {
323
+ setIsDragging(false);
324
+ setCurrentNoteIndex(-1);
325
+ setCurrentNoteTrackIndex(-1);
326
+ window.removeEventListener("mousemove", handleMouseMove);
327
+ window.removeEventListener("mouseup", handleMouseUp);
328
+ };
329
+ window.addEventListener("mousemove", handleMouseMove);
330
+ window.addEventListener("mouseup", handleMouseUp);
331
+ };
332
+ _el$2.$$dblclick = event => {
333
+ event.stopPropagation();
334
+ context.onRemoveNote?.(trackIndex(), noteIndex());
335
+ };
336
+ _el$2.$$mousemove = event => {
337
+ if (isDragging()) return;
338
+ event.stopPropagation();
339
+ const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
340
+ const noteStartX = horizontalViewPort().calculatePixelValue(note.ticks);
341
+ const noteEndX = horizontalViewPort().calculatePixelValue(note.ticks + note.durationTicks);
342
+ setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
343
+ };
344
+ setAttribute(_el$2, "draggable", false);
345
+ effect(_p$ => {
346
+ const _v$ = getClasses(noteDragMode()).join(" "),
347
+ _v$2 = `rgba(255,0,0, ${(128 + note.velocity) / 256})`,
348
+ _v$3 = `${verticalVirtualDimensions().offset}px`,
349
+ _v$4 = `${verticalVirtualDimensions().size}px`,
350
+ _v$5 = `${horizontalDimensions().offset}px`,
351
+ _v$6 = `${horizontalDimensions().size}px`;
352
+ _v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
353
+ _v$2 !== _p$._v$2 && _el$2.style.setProperty("background-color", _p$._v$2 = _v$2);
354
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
355
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
356
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("left", _p$._v$5 = _v$5);
357
+ _v$6 !== _p$._v$6 && _el$2.style.setProperty("width", _p$._v$6 = _v$6);
358
+ return _p$;
359
+ }, {
360
+ _v$: undefined,
361
+ _v$2: undefined,
362
+ _v$3: undefined,
363
+ _v$4: undefined,
364
+ _v$5: undefined,
365
+ _v$6: undefined
366
+ });
367
+ return _el$2;
368
+ }
247
369
  });
248
- };
249
- const handleMouseUp = () => {
250
- setIsDragging(false);
251
- window.removeEventListener("mousemove", handleMouseMove);
252
- window.removeEventListener("mouseup", handleMouseUp);
253
- };
254
- window.addEventListener("mousemove", handleMouseMove);
255
- window.addEventListener("mouseup", handleMouseUp);
256
- };
257
- _el$2.$$dblclick = event => {
258
- event.stopPropagation();
259
- context.onRemoveNote?.(index);
260
- };
261
- _el$2.$$mousemove = event => {
262
- if (isDragging()) return;
263
- event.stopPropagation();
264
- const relativeX = horizontalViewPort().calculatePixelValue(horizontalViewPort().calculatePosition(event.clientX));
265
- const noteStartX = horizontalViewPort().calculatePixelValue(note().ticks);
266
- const noteEndX = horizontalViewPort().calculatePixelValue(note().ticks + note().durationTicks);
267
- setNoteDragMode(relativeX - noteStartX < 3 ? "trimStart" : noteEndX - relativeX < 3 ? "trimEnd" : "move");
268
- };
269
- effect(_p$ => {
270
- const _v$ = getClasses(noteDragMode()).join(" "),
271
- _v$2 = {
272
- "background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
273
- ...(context.condensed ? {
274
- top: 0,
275
- height: "100%"
276
- } : {
277
- top: `${verticalVirtualDimensions().offset}px`,
278
- height: `${verticalVirtualDimensions().size}px`
279
- }),
280
- left: `${horizontalDimensions().offset}px`,
281
- width: `${horizontalDimensions().size}px`
282
- };
283
- _v$ !== _p$._v$ && className(_el$2, _p$._v$ = _v$);
284
- _p$._v$2 = style(_el$2, _v$2, _p$._v$2);
285
- return _p$;
286
- }, {
287
- _v$: undefined,
288
- _v$2: undefined
370
+ }
289
371
  });
290
- return _el$2;
291
372
  }
292
373
  });
293
374
  }
@@ -401,74 +482,11 @@ const ScrollContainer = props => {
401
482
  })();
402
483
  };
403
484
 
404
- var css_248z$1 = ".PianoRollKeys-module_PianoRollKeys__5vnQ0 {\n position: relative;\n height: 100%;\n width: 50px;\n}\n\n.PianoRollKeys-module_Key__jybNC {\n border-width: 0px;\n position: absolute;\n box-sizing: border-box;\n width: 100%;\n border-color: #000;\n border-style: solid;\n border-right-width: 1px;\n}\n\n.PianoRollKeys-module_black__7rncB {\n background: black;\n}\n\n.PianoRollKeys-module_white__fR2Lm {\n background: white;\n}\n\n.PianoRollKeys-module_whiteAndNextIsWhite__PN1O8 {\n border-top-width: 0.1px;\n}\n\n.PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q {\n border-bottom-width: 0.1px;\n}\n";
405
- var styles$1 = {"PianoRollKeys":"PianoRollKeys-module_PianoRollKeys__5vnQ0","Key":"PianoRollKeys-module_Key__jybNC","black":"PianoRollKeys-module_black__7rncB","white":"PianoRollKeys-module_white__fR2Lm","whiteAndNextIsWhite":"PianoRollKeys-module_whiteAndNextIsWhite__PN1O8","whiteAndPreviousIsWhite":"PianoRollKeys-module_whiteAndPreviousIsWhite__-fP3q"};
485
+ var css_248z$1 = ".PianoRollGrid-module_PianoRollGrid__tG119 {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.PianoRollGrid-module_PianoRollGrid-Row__nRMCs {\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";
486
+ var styles$1 = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Row":"PianoRollGrid-module_PianoRollGrid-Row__nRMCs","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
406
487
  styleInject(css_248z$1);
407
488
 
408
489
  const _tmpl$$5 = /*#__PURE__*/template(`<div></div>`, 2);
409
- const PianoRollKeys = () => {
410
- const viewPort = createMemo(() => useViewPortDimension("vertical"));
411
- return (() => {
412
- const _el$ = _tmpl$$5.cloneNode(true);
413
- insert(_el$, createComponent(Index, {
414
- each: keys,
415
- children: key => {
416
- const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
417
- return createComponent(Show, {
418
- get when() {
419
- return virtualDimensions().size > 0;
420
- },
421
- get children() {
422
- const _el$2 = _tmpl$$5.cloneNode(true);
423
- effect(_p$ => {
424
- const _v$ = {
425
- [styles$1["Key"]]: true,
426
- [styles$1["black"]]: key().isBlack,
427
- [styles$1["white"]]: !key().isBlack,
428
- [styles$1["whiteAndNextIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number + 1) % 12),
429
- [styles$1["whiteAndPreviousIsWhite"]]: !key().isBlack && !blackKeys.includes((key().number - 1) % 12)
430
- },
431
- _v$2 = key().name,
432
- _v$3 = key().number % 12,
433
- _v$4 = `${virtualDimensions().offset}px`,
434
- _v$5 = `${virtualDimensions().size}px`;
435
- _p$._v$ = classList(_el$2, _v$, _p$._v$);
436
- _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
437
- _v$3 !== _p$._v$3 && setAttribute(_el$2, "data-index", _p$._v$3 = _v$3);
438
- _v$4 !== _p$._v$4 && _el$2.style.setProperty("top", _p$._v$4 = _v$4);
439
- _v$5 !== _p$._v$5 && _el$2.style.setProperty("height", _p$._v$5 = _v$5);
440
- return _p$;
441
- }, {
442
- _v$: undefined,
443
- _v$2: undefined,
444
- _v$3: undefined,
445
- _v$4: undefined,
446
- _v$5: undefined
447
- });
448
- return _el$2;
449
- }
450
- });
451
- }
452
- }));
453
- effect(() => className(_el$, styles$1.PianoRollKeys));
454
- return _el$;
455
- })();
456
- };
457
- const blackKeys = [1, 3, 6, 8, 10];
458
- const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
459
- const keys = Array.from({
460
- length: 128
461
- }).map((_, index) => ({
462
- number: index,
463
- name: `${keyNames[index % 12]} ${Math.floor(index / 12) - 2}`,
464
- isBlack: blackKeys.includes(index % 12)
465
- }));
466
-
467
- 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";
468
- var styles = {"PianoRollGrid":"PianoRollGrid-module_PianoRollGrid__tG119","PianoRollGrid-Key":"PianoRollGrid-module_PianoRollGrid-Key__VRbiB","PianoRollGrid-Time":"PianoRollGrid-module_PianoRollGrid-Time__jLz3E"};
469
- styleInject(css_248z);
470
-
471
- const _tmpl$$4 = /*#__PURE__*/template(`<div></div>`, 2);
472
490
  const PianoRollGrid = () => {
473
491
  const context = usePianoRollContext();
474
492
  const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
@@ -498,7 +516,7 @@ const PianoRollGrid = () => {
498
516
  }));
499
517
  });
500
518
  return (() => {
501
- const _el$ = _tmpl$$4.cloneNode(true);
519
+ const _el$ = _tmpl$$5.cloneNode(true);
502
520
  insert(_el$, createComponent(Index, {
503
521
  get each() {
504
522
  return gridArray();
@@ -510,9 +528,9 @@ const PianoRollGrid = () => {
510
528
  return virtualDimensions().size > 0;
511
529
  },
512
530
  get children() {
513
- const _el$2 = _tmpl$$4.cloneNode(true);
531
+ const _el$2 = _tmpl$$5.cloneNode(true);
514
532
  effect(_p$ => {
515
- const _v$ = styles["PianoRollGrid-Time"],
533
+ const _v$ = styles$1["PianoRollGrid-Time"],
516
534
  _v$2 = Math.ceil((entry().index + 1 * selectedGridDivisorTicks()) / measureTicks()) % 2 === 0 ? "#ddd" : "#ccc",
517
535
  _v$3 = `${virtualDimensions().offset}px`,
518
536
  _v$4 = `${virtualDimensions().size}px`,
@@ -537,7 +555,7 @@ const PianoRollGrid = () => {
537
555
  }), null);
538
556
  insert(_el$, createComponent(Show, {
539
557
  get when() {
540
- return !context.condensed;
558
+ return context.mode === "keys";
541
559
  },
542
560
  get children() {
543
561
  return createComponent(Index, {
@@ -549,10 +567,10 @@ const PianoRollGrid = () => {
549
567
  return virtualDimensions().size > 0;
550
568
  },
551
569
  get children() {
552
- const _el$3 = _tmpl$$4.cloneNode(true);
570
+ const _el$3 = _tmpl$$5.cloneNode(true);
553
571
  _el$3.style.setProperty("width", "100%");
554
572
  effect(_p$ => {
555
- const _v$6 = styles["PianoRollGrid-Key"],
573
+ const _v$6 = styles$1["PianoRollGrid-Row"],
556
574
  _v$7 = `${virtualDimensions().offset}px`,
557
575
  _v$8 = `${virtualDimensions().size}px`,
558
576
  _v$9 = key().isBlack ? "rgba(0,0,0,0.2)" : "none",
@@ -577,35 +595,53 @@ const PianoRollGrid = () => {
577
595
  });
578
596
  }
579
597
  }), null);
580
- effect(() => className(_el$, styles.PianoRollGrid));
598
+ insert(_el$, createComponent(Show, {
599
+ get when() {
600
+ return context.mode === "tracks";
601
+ },
602
+ get children() {
603
+ return createComponent(For, {
604
+ get each() {
605
+ return context.tracks;
606
+ },
607
+ children: (track, index) => {
608
+ const virtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(index(), 1));
609
+ return createComponent(Show, {
610
+ get when() {
611
+ return virtualDimensions().size > 0;
612
+ },
613
+ get children() {
614
+ const _el$4 = _tmpl$$5.cloneNode(true);
615
+ _el$4.style.setProperty("width", "100%");
616
+ _el$4.style.setProperty("border-width", "0");
617
+ effect(_p$ => {
618
+ const _v$11 = styles$1["PianoRollGrid-Row"],
619
+ _v$12 = `${virtualDimensions().offset}px`,
620
+ _v$13 = `${virtualDimensions().size}px`,
621
+ _v$14 = index() % 2 === 0 ? "rgba(0,0,0,0.2)" : "none";
622
+ _v$11 !== _p$._v$11 && className(_el$4, _p$._v$11 = _v$11);
623
+ _v$12 !== _p$._v$12 && _el$4.style.setProperty("top", _p$._v$12 = _v$12);
624
+ _v$13 !== _p$._v$13 && _el$4.style.setProperty("height", _p$._v$13 = _v$13);
625
+ _v$14 !== _p$._v$14 && _el$4.style.setProperty("background-color", _p$._v$14 = _v$14);
626
+ return _p$;
627
+ }, {
628
+ _v$11: undefined,
629
+ _v$12: undefined,
630
+ _v$13: undefined,
631
+ _v$14: undefined
632
+ });
633
+ return _el$4;
634
+ }
635
+ });
636
+ }
637
+ });
638
+ }
639
+ }), null);
640
+ effect(() => className(_el$, styles$1.PianoRollGrid));
581
641
  return _el$;
582
642
  })();
583
643
  };
584
644
 
585
- const useNotes = () => {
586
- const [notes, onNotesChange] = createSignal([]);
587
- const onNoteChange = (index, note) => {
588
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
589
- };
590
- const onInsertNote = note => {
591
- const index = Math.max(notes().findIndex(({
592
- ticks
593
- }) => ticks > note.ticks), 0);
594
- onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
595
- return index;
596
- };
597
- const onRemoveNote = index => {
598
- onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
599
- };
600
- return {
601
- notes,
602
- onNotesChange,
603
- onNoteChange,
604
- onInsertNote,
605
- onRemoveNote
606
- };
607
- };
608
-
609
645
  const defaultRect = {
610
646
  left: 0,
611
647
  width: 0,
@@ -634,11 +670,11 @@ function useBoundingClientRect(containerRef) {
634
670
  return boundingClientRect;
635
671
  }
636
672
 
637
- const _tmpl$$3 = /*#__PURE__*/template(`<input min="1" max="11" step="0.01">`, 1);
673
+ const _tmpl$$4 = /*#__PURE__*/template(`<input min="1" max="11" step="0.01">`, 1);
638
674
  const VerticalZoomControl = props => {
639
675
  const context = usePianoRollContext();
640
676
  return (() => {
641
- const _el$ = _tmpl$$3.cloneNode(true);
677
+ const _el$ = _tmpl$$4.cloneNode(true);
642
678
  spread(_el$, mergeProps(props, {
643
679
  get value() {
644
680
  return context.verticalZoom;
@@ -662,224 +698,91 @@ const VerticalZoomControl = props => {
662
698
  })();
663
699
  };
664
700
 
665
- const _tmpl$$2 = /*#__PURE__*/template(`<div><ul></ul></div>`, 4),
666
- _tmpl$2 = /*#__PURE__*/template(`<ul></ul>`, 2),
667
- _tmpl$3 = /*#__PURE__*/template(`<div><div></div></div>`, 4),
668
- _tmpl$4 = /*#__PURE__*/template(`<div></div>`, 2),
669
- _tmpl$5 = /*#__PURE__*/template(`<li></li>`, 2);
670
- const MultiTrackPianoRoll = allProps => {
671
- const selectedTrack = createMemo(() => allProps.tracks[allProps.selectedTrackIndex]);
672
- const condensed = createMemo(() => !selectedTrack());
673
- const [ownProps, restProps] = splitProps(allProps, ["tracks", "selectedTrackIndex"]);
674
- const [contextProps, divProps] = splitContextProps(mergeProps$1(restProps, {
675
- notes: [],
676
- condensed: false,
677
- onNoteChange: () => undefined,
678
- onInsertNote: () => -1,
679
- onRemoveNote: () => undefined
680
- }));
681
- const [scrollerRef, setScrollerRef] = createSignal();
682
- const clientRect = useBoundingClientRect(scrollerRef);
683
- const zoomFactor = 500;
684
- const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
685
- const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
686
- const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
687
- const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
701
+ const _tmpl$$3 = /*#__PURE__*/template(`<input max="500" min="1" step="0.01">`, 1);
702
+ const HorizontalZoomControl = props => {
703
+ const context = usePianoRollContext();
688
704
  return (() => {
689
- const _el$ = _tmpl$4.cloneNode(true);
690
- spread(_el$, mergeProps(divProps, {
705
+ const _el$ = _tmpl$$3.cloneNode(true);
706
+ spread(_el$, mergeProps(props, {
707
+ get value() {
708
+ return context.zoom;
709
+ },
710
+ "onInput": event => context.onZoomChange?.(event.currentTarget.valueAsNumber),
711
+ "type": "range",
691
712
  get style() {
692
713
  return {
693
- display: "flex",
694
- flex: 1,
695
- height: "100%",
696
- "flex-direction": "row",
697
- overflow: "hidden",
698
- ...(typeof divProps.style === "object" && divProps.style)
714
+ "margin-left": "50px",
715
+ "margin-right": "16px",
716
+ ...(typeof props.style === "object" && props.style)
699
717
  };
700
718
  }
701
- }), false, true);
702
- insert(_el$, createComponent(PianoRollContextProvider, {
703
- get value() {
704
- return {
705
- ...contextProps
706
- };
719
+ }), false, false);
720
+ return _el$;
721
+ })();
722
+ };
723
+
724
+ var css_248z = ".PianoRollTrackList-module_PianoRollTrackList__pyuxQ {\n position: relative;\n height: 100%;\n flex: 1;\n}\n\n.PianoRollTrackList-module_Track__VZFIg {\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 border-bottom-width: 1px;\n}\n";
725
+ var styles = {"PianoRollTrackList":"PianoRollTrackList-module_PianoRollTrackList__pyuxQ","Track":"PianoRollTrackList-module_Track__VZFIg"};
726
+ styleInject(css_248z);
727
+
728
+ const _tmpl$$2 = /*#__PURE__*/template(`<div></div>`, 2),
729
+ _tmpl$2$1 = /*#__PURE__*/template(`<div> </div>`, 2);
730
+ const PianoRollTrackList = () => {
731
+ const viewPort = createMemo(() => useViewPortDimension("vertical"));
732
+ const context = usePianoRollContext();
733
+ return (() => {
734
+ const _el$ = _tmpl$$2.cloneNode(true);
735
+ insert(_el$, createComponent(Index, {
736
+ get each() {
737
+ return context.tracks;
707
738
  },
708
- get children() {
709
- return createComponent(ScrollZoomViewPort, {
710
- dimensions: {
711
- horizontal: () => ({
712
- pixelOffset: clientRect().left,
713
- pixelSize: clientRect().width,
714
- position: contextProps.position,
715
- range: contextProps.duration,
716
- zoom: contextProps.zoom * (zoomFactor / clientRect().width),
717
- onPositionChange: contextProps.onPositionChange,
718
- onZoomChange: zoom => contextProps.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom()))
719
- }),
720
- vertical: () => ({
721
- pixelOffset: clientRect().top,
722
- pixelSize: clientRect().height,
723
- position: contextProps.verticalPosition,
724
- range: 128,
725
- zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
726
- onPositionChange: contextProps.onVerticalPositionChange,
727
- onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
728
- })
739
+ children: (track, index) => {
740
+ const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(context.mode === "tracks" ? index : index * 8, context.mode === "tracks" ? 1 : 8));
741
+ return createComponent(Show, {
742
+ get when() {
743
+ return virtualDimensions().size > 0;
729
744
  },
730
745
  get children() {
731
- return [(() => {
732
- const _el$2 = _tmpl$$2.cloneNode(true),
733
- _el$3 = _el$2.firstChild;
734
- _el$2.style.setProperty("width", "250px");
735
- _el$2.style.setProperty("display", "flex");
736
- _el$2.style.setProperty("flex-direction", "row");
737
- _el$3.style.setProperty("margin-block-start", "0");
738
- _el$3.style.setProperty("padding-inline-start", "0");
739
- _el$3.style.setProperty("flex", "1");
740
- _el$3.style.setProperty("position", "relative");
741
- insert(_el$3, createComponent(Index, {
742
- get each() {
743
- return allProps.tracks;
744
- },
745
- children: (track, noteIndex) => (() => {
746
- const _el$7 = _tmpl$5.cloneNode(true);
747
- _el$7.$$click = () => {
748
- if (noteIndex === allProps.selectedTrackIndex) {
749
- allProps.onSelectedTrackIndexChange(-1);
750
- } else {
751
- allProps.onSelectedTrackIndexChange(noteIndex);
752
- }
753
- };
754
- _el$7.style.setProperty("width", "100%");
755
- _el$7.style.setProperty("height", "30px");
756
- _el$7.style.setProperty("list-style", "none");
757
- _el$7.style.setProperty("display", "flex");
758
- _el$7.style.setProperty("align-items", "center");
759
- _el$7.style.setProperty("border-top", "1px black solid");
760
- _el$7.style.setProperty("cursor", "pointer");
761
- insert(_el$7, () => track().name);
762
- effect(() => _el$7.style.setProperty("background", noteIndex === allProps.selectedTrackIndex ? "lightgray" : "none"));
763
- return _el$7;
764
- })()
765
- }));
766
- insert(_el$2, createComponent(Show, {
767
- get when() {
768
- return !condensed();
769
- },
770
- get children() {
771
- return createComponent(PianoRollKeys, {});
772
- }
773
- }), null);
774
- return _el$2;
775
- })(), (() => {
776
- const _el$4 = _tmpl$3.cloneNode(true),
777
- _el$5 = _el$4.firstChild;
778
- _el$4.style.setProperty("flex", "1");
779
- insert(_el$5, createComponent(ScrollContainer, {
780
- ref: setScrollerRef,
781
- get children() {
782
- return [memo(() => allProps.children), (() => {
783
- const _el$6 = _tmpl$2.cloneNode(true);
784
- _el$6.style.setProperty("margin", "0");
785
- _el$6.style.setProperty("margin-block-start", "0");
786
- _el$6.style.setProperty("padding-inline-start", "0");
787
- insert(_el$6, createComponent(Index, {
788
- get each() {
789
- return allProps.tracks;
790
- },
791
- children: (track, trackIndex) => {
792
- const notes = useNotes();
793
- createEffect(() => {
794
- notes.onNotesChange(track().notes);
795
- });
796
- const [context, setContext] = createStore({
797
- ...contextProps
798
- });
799
- createEffect(() => {
800
- setContext({
801
- ...contextProps,
802
- condensed: condensed(),
803
- notes: track()?.notes,
804
- onNoteChange: (noteIndex, note) => allProps?.onNoteChange?.(trackIndex, noteIndex, note),
805
- onInsertNote: note => allProps.onInsertNote?.(trackIndex, note) ?? -1,
806
- onRemoveNote: noteIndex => allProps.onRemoveNote?.(trackIndex, noteIndex)
807
- });
808
- });
809
- const verticalViewPort = useViewPortDimension("vertical");
810
- return createComponent(Show, {
811
- get when() {
812
- return condensed() || allProps.selectedTrackIndex === trackIndex;
813
- },
814
- get children() {
815
- return createComponent(PianoRollContextProvider, {
816
- value: context,
817
- get children() {
818
- const _el$8 = _tmpl$5.cloneNode(true);
819
- _el$8.style.setProperty("display", "flex");
820
- _el$8.style.setProperty("position", "relative");
821
- _el$8.style.setProperty("list-style", "none");
822
- _el$8.style.setProperty("flex-direction", "row");
823
- _el$8.style.setProperty("border-top", "1px black solid");
824
- insert(_el$8, createComponent(PianoRollNotes, {}), null);
825
- insert(_el$8, createComponent(PianoRollGrid, {}), null);
826
- effect(() => _el$8.style.setProperty("height", condensed() ? "30px" : `${verticalViewPort.pixelSize}px`));
827
- return _el$8;
828
- }
829
- });
830
- }
831
- });
832
- }
833
- }));
834
- return _el$6;
835
- })()];
836
- }
837
- }), null);
838
- insert(_el$5, createComponent(Show, {
839
- get when() {
840
- return !condensed();
841
- },
842
- get children() {
843
- return createComponent(VerticalZoomControl, {
844
- get value() {
845
- return contextProps.verticalZoom;
846
- },
847
- onInput: event => contextProps.onVerticalZoomChange?.(event.currentTarget.valueAsNumber)
848
- });
849
- }
850
- }), null);
851
- insert(_el$4, createComponent(HorizontalZoomControl, {
852
- style: {
853
- width: "100%",
854
- "margin-left": 0
855
- },
856
- get value() {
857
- return contextProps.zoom;
746
+ const _el$2 = _tmpl$2$1.cloneNode(true),
747
+ _el$3 = _el$2.firstChild;
748
+ _el$2.$$click = () => context.onSelectedTrackIndexChange?.(index);
749
+ _el$2.style.setProperty("cursor", "pointer");
750
+ insert(_el$2, index, _el$3);
751
+ insert(_el$2, () => track().name || "[unnamed track]", null);
752
+ effect(_p$ => {
753
+ const _v$ = {
754
+ [styles["Track"]]: true
858
755
  },
859
- onInput: event => contextProps.onZoomChange?.(event.currentTarget.valueAsNumber)
860
- }), null);
861
- effect(_p$ => {
862
- const _v$ = styles$3.PianoRoll,
863
- _v$2 = styles$3.PianoRollContainer;
864
- _v$ !== _p$._v$ && className(_el$4, _p$._v$ = _v$);
865
- _v$2 !== _p$._v$2 && className(_el$5, _p$._v$2 = _v$2);
866
- return _p$;
867
- }, {
868
- _v$: undefined,
869
- _v$2: undefined
870
- });
871
- return _el$4;
872
- })()];
756
+ _v$2 = track().name,
757
+ _v$3 = `${virtualDimensions().offset}px`,
758
+ _v$4 = `${virtualDimensions().size}px`,
759
+ _v$5 = index === context.selectedTrackIndex ? "gray" : "lightgrey";
760
+ _p$._v$ = classList(_el$2, _v$, _p$._v$);
761
+ _v$2 !== _p$._v$2 && setAttribute(_el$2, "title", _p$._v$2 = _v$2);
762
+ _v$3 !== _p$._v$3 && _el$2.style.setProperty("top", _p$._v$3 = _v$3);
763
+ _v$4 !== _p$._v$4 && _el$2.style.setProperty("height", _p$._v$4 = _v$4);
764
+ _v$5 !== _p$._v$5 && _el$2.style.setProperty("background", _p$._v$5 = _v$5);
765
+ return _p$;
766
+ }, {
767
+ _v$: undefined,
768
+ _v$2: undefined,
769
+ _v$3: undefined,
770
+ _v$4: undefined,
771
+ _v$5: undefined
772
+ });
773
+ return _el$2;
873
774
  }
874
775
  });
875
776
  }
876
777
  }));
778
+ effect(() => className(_el$, styles.PianoRollTrackList));
877
779
  return _el$;
878
780
  })();
879
781
  };
880
782
  delegateEvents(["click"]);
881
783
 
882
- const _tmpl$$1 = /*#__PURE__*/template(`<div><div></div></div>`, 4);
784
+ const _tmpl$$1 = /*#__PURE__*/template(`<div></div>`, 2),
785
+ _tmpl$2 = /*#__PURE__*/template(`<div><div></div></div>`, 4);
883
786
  const PianoRoll = allProps => {
884
787
  const [contextProps, divProps] = splitContextProps(allProps);
885
788
  const [scrollerRef, setScrollerRef] = createSignal();
@@ -889,14 +792,20 @@ const PianoRoll = allProps => {
889
792
  const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
890
793
  const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
891
794
  const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
795
+ createEffect(isInitial => {
796
+ if (isInitial) return false;
797
+ if (contextProps.mode === "tracks") {
798
+ contextProps.onVerticalPositionChange?.(0);
799
+ }
800
+ }, true);
892
801
  return createComponent(PianoRollContextProvider, {
893
802
  value: contextProps,
894
803
  get children() {
895
- const _el$ = _tmpl$$1.cloneNode(true),
804
+ const _el$ = _tmpl$2.cloneNode(true),
896
805
  _el$2 = _el$.firstChild;
897
806
  spread(_el$, mergeProps(divProps, {
898
807
  get ["class"]() {
899
- return styles$3.PianoRoll;
808
+ return styles$4.PianoRoll;
900
809
  }
901
810
  }), false, true);
902
811
  insert(_el$2, createComponent(ScrollZoomViewPort, {
@@ -914,14 +823,35 @@ const PianoRoll = allProps => {
914
823
  pixelOffset: clientRect().top,
915
824
  pixelSize: clientRect().height,
916
825
  position: contextProps.verticalPosition,
917
- range: 128,
826
+ range: contextProps.mode === "keys" ? 128 : Math.max(contextProps.tracks.length, 16),
918
827
  zoom: contextProps.verticalZoom * (zoomFactor / clientRect().height),
919
828
  onPositionChange: contextProps.onVerticalPositionChange,
920
829
  onZoomChange: verticalZoom => contextProps.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom()))
921
830
  })
922
831
  },
923
832
  get children() {
924
- return [createComponent(PianoRollKeys, {}), createComponent(ScrollContainer, {
833
+ return [(() => {
834
+ const _el$3 = _tmpl$$1.cloneNode(true);
835
+ _el$3.style.setProperty("display", "flex");
836
+ _el$3.style.setProperty("width", "20%");
837
+ insert(_el$3, createComponent(Show, {
838
+ get when() {
839
+ return allProps.showTrackList;
840
+ },
841
+ get children() {
842
+ return createComponent(PianoRollTrackList, {});
843
+ }
844
+ }), null);
845
+ insert(_el$3, createComponent(Show, {
846
+ get when() {
847
+ return contextProps.mode === "keys";
848
+ },
849
+ get children() {
850
+ return createComponent(PianoRollKeys, {});
851
+ }
852
+ }), null);
853
+ return _el$3;
854
+ })(), createComponent(ScrollContainer, {
925
855
  ref: setScrollerRef,
926
856
  get children() {
927
857
  return [memo(() => allProps.children), createComponent(PianoRollGrid, {}), createComponent(PianoRollNotes, {})];
@@ -944,7 +874,7 @@ const PianoRoll = allProps => {
944
874
  return maxZoom();
945
875
  }
946
876
  }), null);
947
- effect(() => className(_el$2, styles$3.PianoRollContainer));
877
+ effect(() => className(_el$2, styles$4.PianoRollContainer));
948
878
  return _el$;
949
879
  }
950
880
  });
@@ -1004,13 +934,37 @@ const PlayHead = allProps => {
1004
934
  })();
1005
935
  };
1006
936
 
937
+ const useNotes = () => {
938
+ const [notes, onNotesChange] = createSignal([]);
939
+ const onNoteChange = (index, note) => {
940
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
941
+ };
942
+ const onInsertNote = note => {
943
+ const index = Math.max(notes().findIndex(({
944
+ ticks
945
+ }) => ticks > note.ticks), 0);
946
+ onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
947
+ return index;
948
+ };
949
+ const onRemoveNote = index => {
950
+ onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
951
+ };
952
+ return {
953
+ notes,
954
+ onNotesChange,
955
+ onNoteChange,
956
+ onInsertNote,
957
+ onRemoveNote
958
+ };
959
+ };
960
+
1007
961
  const usePianoRoll = () => {
1008
962
  const [ppq, onPpqChange] = createSignal(120);
1009
- const [condensed, onCondensedChange] = createSignal(false);
963
+ const [mode, onModeChange] = createSignal("tracks");
1010
964
  const [position, onPositionChange] = createSignal(0);
1011
965
  const [zoom, onZoomChange] = createSignal(10);
1012
966
  const [verticalZoom, onVerticalZoomChange] = createSignal(5);
1013
- const [verticalPosition, onVerticalPositionChange] = createSignal(64);
967
+ const [verticalPosition, onVerticalPositionChange] = createSignal(44);
1014
968
  const [gridDivision, onGridDivisionChange] = createSignal(4);
1015
969
  const [snapToGrid, onSnapToGridChange] = createSignal(true);
1016
970
  const [duration, onDurationChange] = createSignal(0);
@@ -1029,12 +983,12 @@ const usePianoRoll = () => {
1029
983
  onGridDivisionChange,
1030
984
  snapToGrid,
1031
985
  onSnapToGridChange,
1032
- condensed,
1033
- onCondensedChange,
986
+ mode,
987
+ onModeChange,
1034
988
  duration,
1035
989
  onDurationChange
1036
990
  };
1037
991
  };
1038
992
 
1039
- export { MultiTrackPianoRoll, PianoRoll, PlayHead, useNotes, usePianoRoll };
993
+ export { PianoRoll, PlayHead, useNotes, usePianoRoll };
1040
994
  //# sourceMappingURL=index.js.map