solid-pianoroll 0.0.10 → 0.0.12
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 +340 -140
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +341 -143
- package/dist/esm/index.js.map +1 -1
- package/dist/source/MultiTrackPianoRoll.jsx +136 -0
- package/dist/source/PianoRoll.jsx +3 -20
- package/dist/source/PianoRollContext.jsx +20 -1
- package/dist/source/PianoRollNotes.jsx +14 -7
- package/dist/source/index.jsx +3 -1
- package/dist/source/useNotes.js +23 -0
- package/dist/source/usePianoRoll.js +4 -24
- package/dist/source/viewport/HorizontalZoomControl.jsx +1 -0
- package/dist/source/viewport/createViewPortDimension.js +4 -0
- package/dist/types/MultiTrackPianoRoll.d.ts +10 -0
- package/dist/types/PianoRollContext.d.ts +1 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/useNotes.d.ts +9 -0
- package/dist/types/usePianoRoll.d.ts +2 -6
- package/dist/types/viewport/ScrollZoomViewPort.d.ts +4 -0
- package/dist/types/viewport/createViewPortDimension.d.ts +4 -0
- package/package.json +1 -1
|
@@ -12,7 +12,9 @@ const PianoRollNotes = (props) => {
|
|
|
12
12
|
: value;
|
|
13
13
|
const insertOrUpdateNote = (event) => {
|
|
14
14
|
const position = horizontalViewPort().calculatePosition(event.clientX);
|
|
15
|
-
const midi =
|
|
15
|
+
const midi = context.condensed
|
|
16
|
+
? 60
|
|
17
|
+
: 127 - Math.floor(verticalViewPort().calculatePosition(event.clientY));
|
|
16
18
|
const eventPositionTicks = Math.floor(position / gridDivisionTicks()) * gridDivisionTicks();
|
|
17
19
|
const velocity = 127;
|
|
18
20
|
const existingNote = newNote();
|
|
@@ -48,7 +50,6 @@ const PianoRollNotes = (props) => {
|
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
50
52
|
const index = insertOrUpdateNote(event);
|
|
51
|
-
console.log({ index });
|
|
52
53
|
setNewNoteIndex(index);
|
|
53
54
|
}} onMouseUp={(event) => {
|
|
54
55
|
setIsMouseDown(false);
|
|
@@ -68,9 +69,10 @@ const PianoRollNotes = (props) => {
|
|
|
68
69
|
}}>
|
|
69
70
|
<Index each={context.notes}>
|
|
70
71
|
{(note, index) => {
|
|
71
|
-
const
|
|
72
|
+
const verticalVirtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - note().midi, 1));
|
|
72
73
|
const horizontalDimensions = createMemo(() => horizontalViewPort().calculatePixelDimensions(note().ticks, note().durationTicks));
|
|
73
|
-
return (<Show when={
|
|
74
|
+
return (<Show when={(verticalViewPort().isVisible(verticalVirtualDimensions()) || context.condensed) &&
|
|
75
|
+
horizontalViewPort().isVisible(horizontalDimensions())}>
|
|
74
76
|
<div class={getClasses(noteDragMode()).join(" ")} onMouseMove={(event) => {
|
|
75
77
|
if (isDragging())
|
|
76
78
|
return;
|
|
@@ -96,7 +98,8 @@ const PianoRollNotes = (props) => {
|
|
|
96
98
|
diffPosition, 0), mouseMoveEvent.altKey);
|
|
97
99
|
context.onNoteChange?.(index, {
|
|
98
100
|
...note(),
|
|
99
|
-
...(noteDragMode() === "move" &&
|
|
101
|
+
...(noteDragMode() === "move" &&
|
|
102
|
+
!context.condensed && {
|
|
100
103
|
midi: Math.round(127 - verticalViewPort().calculatePosition(mouseMoveEvent.clientY)),
|
|
101
104
|
}),
|
|
102
105
|
...((noteDragMode() === "move" || noteDragMode() === "trimStart") && {
|
|
@@ -120,8 +123,12 @@ const PianoRollNotes = (props) => {
|
|
|
120
123
|
window.addEventListener("mouseup", handleMouseUp);
|
|
121
124
|
}} style={{
|
|
122
125
|
"background-color": `rgba(255,0,0, ${(128 + note().velocity) / 256})`,
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
...(context.condensed
|
|
127
|
+
? { top: 0, height: "100%" }
|
|
128
|
+
: {
|
|
129
|
+
top: `${verticalVirtualDimensions().offset}px`,
|
|
130
|
+
height: `${verticalVirtualDimensions().size}px`,
|
|
131
|
+
}),
|
|
125
132
|
left: `${horizontalDimensions().offset}px`,
|
|
126
133
|
width: `${horizontalDimensions().size}px`,
|
|
127
134
|
}}></div>
|
package/dist/source/index.jsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import MultiTrackPianoRoll from "./MultiTrackPianoRoll";
|
|
1
2
|
import PianoRoll from "./PianoRoll";
|
|
3
|
+
import useNotes from "./useNotes";
|
|
2
4
|
import usePianoRoll from "./usePianoRoll";
|
|
3
|
-
export { PianoRoll, usePianoRoll };
|
|
5
|
+
export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createSignal } from "solid-js";
|
|
2
|
+
const useNotes = () => {
|
|
3
|
+
const [notes, onNotesChange] = createSignal([]);
|
|
4
|
+
const onNoteChange = (index, note) => {
|
|
5
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
6
|
+
};
|
|
7
|
+
const onInsertNote = (note) => {
|
|
8
|
+
const index = Math.max(notes().findIndex(({ ticks }) => ticks > note.ticks), 0);
|
|
9
|
+
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
|
|
10
|
+
return index;
|
|
11
|
+
};
|
|
12
|
+
const onRemoveNote = (index) => {
|
|
13
|
+
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
notes,
|
|
17
|
+
onNotesChange,
|
|
18
|
+
onNoteChange,
|
|
19
|
+
onInsertNote,
|
|
20
|
+
onRemoveNote,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export default useNotes;
|
|
@@ -1,31 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSignal } from "solid-js";
|
|
2
2
|
const usePianoRoll = () => {
|
|
3
3
|
const [ppq, onPpqChange] = createSignal(120);
|
|
4
|
+
const [condensed, onCondensedChange] = createSignal(false);
|
|
4
5
|
const [position, onPositionChange] = createSignal(0);
|
|
5
6
|
const [zoom, onZoomChange] = createSignal(10);
|
|
6
7
|
const [verticalZoom, onVerticalZoomChange] = createSignal(5);
|
|
7
8
|
const [verticalPosition, onVerticalPositionChange] = createSignal(64);
|
|
8
9
|
const [gridDivision, onGridDivisionChange] = createSignal(16);
|
|
9
10
|
const [snapToGrid, onSnapToGridChange] = createSignal(true);
|
|
10
|
-
const [notes, onNotesChange] = createSignal([]);
|
|
11
11
|
const [duration, onDurationChange] = createSignal(0);
|
|
12
|
-
const onNoteChange = (index, note) => {
|
|
13
|
-
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index + 1)]);
|
|
14
|
-
};
|
|
15
|
-
const onInsertNote = (note) => {
|
|
16
|
-
const index = Math.max(notes().findIndex(({ ticks }) => ticks > note.ticks), 0);
|
|
17
|
-
onNotesChange([...notes().slice(0, index), note, ...notes().splice(index)]);
|
|
18
|
-
return index;
|
|
19
|
-
};
|
|
20
|
-
const onRemoveNote = (index) => {
|
|
21
|
-
onNotesChange([...notes().slice(0, index), ...notes().splice(index + 1)]);
|
|
22
|
-
};
|
|
23
|
-
createEffect(() => {
|
|
24
|
-
const minDuration = Math.max((notes()[notes().length - 1]?.ticks ?? 0) + (notes()[notes().length - 1]?.durationTicks ?? 0), ppq() * 4 * 4);
|
|
25
|
-
if (duration() < minDuration) {
|
|
26
|
-
onDurationChange(minDuration);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
12
|
return {
|
|
30
13
|
ppq,
|
|
31
14
|
onPpqChange,
|
|
@@ -41,11 +24,8 @@ const usePianoRoll = () => {
|
|
|
41
24
|
onGridDivisionChange,
|
|
42
25
|
snapToGrid,
|
|
43
26
|
onSnapToGridChange,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
onNoteChange,
|
|
47
|
-
onInsertNote,
|
|
48
|
-
onRemoveNote,
|
|
27
|
+
condensed,
|
|
28
|
+
onCondensedChange,
|
|
49
29
|
duration,
|
|
50
30
|
onDurationChange,
|
|
51
31
|
};
|
|
@@ -4,6 +4,7 @@ const HorizontalZoomControl = (props) => {
|
|
|
4
4
|
return (<input max="500" min="1" step={0.01} {...props} value={context.zoom} onInput={(event) => context.onZoomChange?.(event.currentTarget.valueAsNumber)} type="range" style={{
|
|
5
5
|
"margin-left": "50px",
|
|
6
6
|
"margin-right": "16px",
|
|
7
|
+
...(typeof props.style === "object" && props.style),
|
|
7
8
|
}}/>);
|
|
8
9
|
};
|
|
9
10
|
export default HorizontalZoomControl;
|
|
@@ -8,6 +8,7 @@ export default function createViewPortDimension(getState) {
|
|
|
8
8
|
calculatePixelDimensions,
|
|
9
9
|
calculateVisibleRange,
|
|
10
10
|
calculateMaxPosition,
|
|
11
|
+
isVisible,
|
|
11
12
|
});
|
|
12
13
|
const [state, setState] = createStore(getStateWithFunctions());
|
|
13
14
|
createEffect(() => setState(getStateWithFunctions()));
|
|
@@ -34,6 +35,9 @@ export default function createViewPortDimension(getState) {
|
|
|
34
35
|
const size = calculatePixelValue(length);
|
|
35
36
|
return { offset, size };
|
|
36
37
|
}
|
|
38
|
+
function isVisible({ offset, size }) {
|
|
39
|
+
return offset + size > 0 && offset < state.pixelSize;
|
|
40
|
+
}
|
|
37
41
|
return state;
|
|
38
42
|
}
|
|
39
43
|
export const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { JSX } from "solid-js";
|
|
2
|
+
import { TrackJSON } from "@tonejs/midi";
|
|
3
|
+
import { PianoRollProps } from "./PianoRoll";
|
|
4
|
+
export type MultiTrackPianoRollProps = Omit<PianoRollProps, "notes" | "onNoteChange" | "onInsertNote" | "onRemoveNote" | "condensed"> & {
|
|
5
|
+
tracks: TrackJSON[];
|
|
6
|
+
selectedTrack?: TrackJSON;
|
|
7
|
+
onSelectedTrackChange: (track?: TrackJSON) => void;
|
|
8
|
+
} & JSX.IntrinsicElements["div"];
|
|
9
|
+
declare const MultiTrackPianoRoll: (allProps: MultiTrackPianoRollProps) => JSX.Element;
|
|
10
|
+
export default MultiTrackPianoRoll;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { PianoRollProps } from "./PianoRoll";
|
|
2
2
|
export declare const PianoRollContextProvider: import("solid-js/types/reactive/signal").ContextProviderComponent<PianoRollProps>;
|
|
3
3
|
export declare const usePianoRollContext: () => PianoRollProps;
|
|
4
|
+
export declare const splitContextProps: (allProps: PianoRollProps) => [Pick<PianoRollProps, "position" | "condensed" | "zoom" | "onZoomChange" | "onPositionChange" | "notes" | "duration" | "gridDivision" | "ppq" | "snapToGrid" | "verticalPosition" | "verticalZoom" | "onInsertNote" | "onNoteChange" | "onRemoveNote" | "onVerticalPositionChange" | "onVerticalZoomChange">, Omit<PianoRollProps, "position" | "condensed" | "zoom" | "onZoomChange" | "onPositionChange" | "notes" | "duration" | "gridDivision" | "ppq" | "snapToGrid" | "verticalPosition" | "verticalZoom" | "onInsertNote" | "onNoteChange" | "onRemoveNote" | "onVerticalPositionChange" | "onVerticalZoomChange">];
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import MultiTrackPianoRoll from "./MultiTrackPianoRoll";
|
|
1
2
|
import PianoRoll from "./PianoRoll";
|
|
3
|
+
import useNotes from "./useNotes";
|
|
2
4
|
import usePianoRoll from "./usePianoRoll";
|
|
3
|
-
export { PianoRoll, usePianoRoll };
|
|
5
|
+
export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Note } from "./types";
|
|
2
|
+
declare const useNotes: () => {
|
|
3
|
+
notes: import("solid-js").Accessor<Note[]>;
|
|
4
|
+
onNotesChange: import("solid-js").Setter<Note[]>;
|
|
5
|
+
onNoteChange: (index: number, note: Note) => void;
|
|
6
|
+
onInsertNote: (note: Note) => number;
|
|
7
|
+
onRemoveNote: (index: number) => void;
|
|
8
|
+
};
|
|
9
|
+
export default useNotes;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { GridDivision } from "./PianoRoll";
|
|
2
|
-
import { Note } from "./types";
|
|
3
2
|
declare const usePianoRoll: () => {
|
|
4
3
|
ppq: import("solid-js").Accessor<number>;
|
|
5
4
|
onPpqChange: import("solid-js").Setter<number>;
|
|
@@ -15,11 +14,8 @@ declare const usePianoRoll: () => {
|
|
|
15
14
|
onGridDivisionChange: import("solid-js").Setter<GridDivision>;
|
|
16
15
|
snapToGrid: import("solid-js").Accessor<boolean>;
|
|
17
16
|
onSnapToGridChange: import("solid-js").Setter<boolean>;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
onNoteChange: (index: number, note: Note) => void;
|
|
21
|
-
onInsertNote: (note: Note) => number;
|
|
22
|
-
onRemoveNote: (index: number) => void;
|
|
17
|
+
condensed: import("solid-js").Accessor<boolean>;
|
|
18
|
+
onCondensedChange: import("solid-js").Setter<boolean>;
|
|
23
19
|
duration: import("solid-js").Accessor<number>;
|
|
24
20
|
onDurationChange: import("solid-js").Setter<number>;
|
|
25
21
|
};
|
|
@@ -12,6 +12,10 @@ export declare const useViewPortDimension: (name: ViewPortDimensionName) => {
|
|
|
12
12
|
};
|
|
13
13
|
calculateVisibleRange: () => number;
|
|
14
14
|
calculateMaxPosition: () => number;
|
|
15
|
+
isVisible: ({ offset, size }: {
|
|
16
|
+
offset: number;
|
|
17
|
+
size: number;
|
|
18
|
+
}) => boolean;
|
|
15
19
|
position: number;
|
|
16
20
|
range: number;
|
|
17
21
|
pixelOffset: number;
|
|
@@ -19,6 +19,10 @@ export default function createViewPortDimension(getState: () => ViewPortDimensio
|
|
|
19
19
|
};
|
|
20
20
|
calculateVisibleRange: () => number;
|
|
21
21
|
calculateMaxPosition: () => number;
|
|
22
|
+
isVisible: ({ offset, size }: {
|
|
23
|
+
offset: number;
|
|
24
|
+
size: number;
|
|
25
|
+
}) => boolean;
|
|
22
26
|
position: number;
|
|
23
27
|
range: number;
|
|
24
28
|
pixelOffset: number;
|
package/package.json
CHANGED