solid-pianoroll 0.0.13 → 0.0.14

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.
@@ -10,10 +10,13 @@ const PianoRollGrid = () => {
10
10
  const measureTicks = createMemo(() => context.ppq * 4);
11
11
  const selectedGridDivisorTicks = createMemo(() => measureTicks() / context.gridDivision);
12
12
  function calculateVisibleGridDivisorTicks(value) {
13
- if (horizontalViewPort().calculateVisibleRange() / value > 100) {
13
+ const visibleRange = horizontalViewPort().calculateVisibleRange();
14
+ if (visibleRange <= 0)
15
+ return 0;
16
+ if (visibleRange / value > 100) {
14
17
  return calculateVisibleGridDivisorTicks(value * 2);
15
18
  }
16
- if (horizontalViewPort().calculateVisibleRange() / value < 30) {
19
+ if (visibleRange / value < 30) {
17
20
  return calculateVisibleGridDivisorTicks(value / 2);
18
21
  }
19
22
  return value;
@@ -0,0 +1,47 @@
1
+ import { createEffect, createMemo, mergeProps, splitProps } from "solid-js";
2
+ import { clamp } from "./viewport/createViewPortDimension";
3
+ import { useViewPortDimension } from "./viewport/ScrollZoomViewPort";
4
+ const PlayHead = (allProps) => {
5
+ const propsWithDefauls = mergeProps({ playHeadPosition: 0, sync: false }, allProps);
6
+ const [props, divProps] = splitProps(propsWithDefauls, [
7
+ "playHeadPosition",
8
+ "sync",
9
+ "onPlayHeadPositionChange",
10
+ "onPositionChange",
11
+ ]);
12
+ const viewPort = useViewPortDimension("horizontal");
13
+ createEffect(() => {
14
+ if (!props.sync)
15
+ return;
16
+ const maxPosition = viewPort.range;
17
+ const newPosition = clamp(props.playHeadPosition - viewPort.range / viewPort.zoom / 2, 0, maxPosition);
18
+ props.onPositionChange?.(newPosition);
19
+ });
20
+ const leftPosition = createMemo(() => viewPort.calculatePixelOffset(props.playHeadPosition));
21
+ return (<div class="PlayHead" {...divProps} style={{
22
+ position: "absolute",
23
+ height: "100%",
24
+ width: "2px",
25
+ left: `${leftPosition()}px`,
26
+ "background-color": "green",
27
+ cursor: "pointer",
28
+ ...(typeof divProps.style === "object" && divProps.style),
29
+ }} onMouseDown={(event) => {
30
+ event.preventDefault();
31
+ event.stopPropagation();
32
+ const handleMouseMove = ({ movementX }) => {
33
+ const { parentElement } = event.currentTarget;
34
+ if (!parentElement)
35
+ return;
36
+ const newPosition = viewPort.calculatePosition(leftPosition() + movementX);
37
+ props.onPlayHeadPositionChange?.(newPosition);
38
+ };
39
+ const handleMouseUp = () => {
40
+ window.removeEventListener("mousemove", handleMouseMove);
41
+ window.removeEventListener("mouseup", handleMouseUp);
42
+ };
43
+ window.addEventListener("mousemove", handleMouseMove);
44
+ window.addEventListener("mouseup", handleMouseUp);
45
+ }}/>);
46
+ };
47
+ export default PlayHead;
@@ -1,5 +1,6 @@
1
1
  import MultiTrackPianoRoll from "./MultiTrackPianoRoll";
2
2
  import PianoRoll from "./PianoRoll";
3
+ import PlayHead from "./PlayHead";
3
4
  import useNotes from "./useNotes";
4
5
  import usePianoRoll from "./usePianoRoll";
5
- export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes };
6
+ export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes, PlayHead };
@@ -3,6 +3,7 @@ import { createStore } from "solid-js/store";
3
3
  export default function createViewPortDimension(getState) {
4
4
  const getStateWithFunctions = () => ({
5
5
  ...getState(),
6
+ calculatePixelOffset,
6
7
  calculatePixelValue,
7
8
  calculatePosition,
8
9
  calculatePixelDimensions,
@@ -1,10 +1,13 @@
1
- import { JSX } from "solid-js";
2
- import { TrackJSON } from "@tonejs/midi";
1
+ import { JSX, ParentProps } from "solid-js";
3
2
  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;
3
+ import { Note, Track } from "./types";
4
+ export type MultiTrackPianoRollProps = Omit<PianoRollProps, "condensed" | "notes" | "onNoteChange" | "onInsertNote" | "onRemoveNote"> & {
5
+ tracks: Track[];
6
+ selectedTrackIndex: number;
7
+ onSelectedTrackIndexChange: (trackIndex: number) => void;
8
+ onNoteChange?: (trackIndex: number, index: number, note: Note) => void;
9
+ onInsertNote?: (trackIndex: number, note: Note) => number;
10
+ onRemoveNote?: (trackIndex: number, index: number) => void;
8
11
  } & JSX.IntrinsicElements["div"];
9
- declare const MultiTrackPianoRoll: (allProps: MultiTrackPianoRollProps) => JSX.Element;
12
+ declare const MultiTrackPianoRoll: (allProps: ParentProps<MultiTrackPianoRollProps>) => JSX.Element;
10
13
  export default MultiTrackPianoRoll;
@@ -1,4 +1,4 @@
1
- import { JSX } from "solid-js";
1
+ import { JSX, ParentProps } from "solid-js";
2
2
  import { Note } from "./types";
3
3
  export type GridDivision = 1 | 2 | 4 | 8 | 16 | 32 | 64;
4
4
  export type PianoRollProps = {
@@ -20,5 +20,5 @@ export type PianoRollProps = {
20
20
  onInsertNote?: (note: Note) => number;
21
21
  onRemoveNote?: (index: number) => void;
22
22
  };
23
- declare const PianoRoll: (allProps: PianoRollProps & JSX.IntrinsicElements["div"]) => JSX.Element;
23
+ declare const PianoRoll: (allProps: ParentProps<PianoRollProps & JSX.IntrinsicElements["div"]>) => JSX.Element;
24
24
  export default PianoRoll;
@@ -1,4 +1,5 @@
1
+ import { JSX } from "solid-js";
1
2
  import { PianoRollProps } from "./PianoRoll";
2
3
  export declare const PianoRollContextProvider: import("solid-js/types/reactive/signal").ContextProviderComponent<PianoRollProps>;
3
4
  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">];
5
+ export declare const splitContextProps: (allProps: PianoRollProps & JSX.IntrinsicElements["div"]) => [Pick<PianoRollProps & JSX.HTMLAttributes<HTMLDivElement>, "position" | "condensed" | "zoom" | "onZoomChange" | "onPositionChange" | "notes" | "duration" | "gridDivision" | "ppq" | "snapToGrid" | "verticalPosition" | "verticalZoom" | "onInsertNote" | "onNoteChange" | "onRemoveNote" | "onVerticalPositionChange" | "onVerticalZoomChange">, Omit<PianoRollProps & JSX.HTMLAttributes<HTMLDivElement>, "position" | "condensed" | "zoom" | "onZoomChange" | "onPositionChange" | "notes" | "duration" | "gridDivision" | "ppq" | "snapToGrid" | "verticalPosition" | "verticalZoom" | "onInsertNote" | "onNoteChange" | "onRemoveNote" | "onVerticalPositionChange" | "onVerticalZoomChange">];
@@ -0,0 +1,8 @@
1
+ import { JSX } from "solid-js";
2
+ declare const PlayHead: (allProps: {
3
+ playHeadPosition?: number;
4
+ sync?: boolean;
5
+ onPlayHeadPositionChange?: (playHeadPosition: number) => void;
6
+ onPositionChange?: (position: number) => void;
7
+ } & JSX.HTMLAttributes<HTMLDivElement>) => JSX.Element;
8
+ export default PlayHead;
@@ -1,5 +1,6 @@
1
1
  import MultiTrackPianoRoll from "./MultiTrackPianoRoll";
2
2
  import PianoRoll from "./PianoRoll";
3
+ import PlayHead from "./PlayHead";
3
4
  import useNotes from "./useNotes";
4
5
  import usePianoRoll from "./usePianoRoll";
5
- export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes };
6
+ export { PianoRoll, MultiTrackPianoRoll, usePianoRoll, useNotes, PlayHead };
@@ -1,2 +1,6 @@
1
1
  import { Midi } from "@tonejs/midi";
2
2
  export type Note = Pick<ReturnType<Midi["tracks"][number]["notes"][number]["toJSON"]>, "durationTicks" | "midi" | "ticks" | "velocity">;
3
+ export type Track = {
4
+ name: string;
5
+ notes: Note[];
6
+ };
@@ -4,6 +4,7 @@ export declare const ScrollZoomViewPort: (props: ParentProps<{
4
4
  dimensions: Record<ViewPortDimensionName, () => Omit<ViewPortDimensionState, "name">>;
5
5
  }>) => import("solid-js").JSX.Element;
6
6
  export declare const useViewPortDimension: (name: ViewPortDimensionName) => {
7
+ calculatePixelOffset: (position: number) => number;
7
8
  calculatePixelValue: (position?: number) => number;
8
9
  calculatePosition: (offset: number) => number;
9
10
  calculatePixelDimensions: (position: number, length: number) => {
@@ -11,6 +11,7 @@ export type ViewPortDimensionState = {
11
11
  zoom: number;
12
12
  };
13
13
  export default function createViewPortDimension(getState: () => ViewPortDimensionState): {
14
+ calculatePixelOffset: (position: number) => number;
14
15
  calculatePixelValue: (position?: number) => number;
15
16
  calculatePosition: (offset: number) => number;
16
17
  calculatePixelDimensions: (position: number, length: number) => {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.13",
2
+ "version": "0.0.14",
3
3
  "name": "solid-pianoroll",
4
4
  "description": "Pianoroll UI Control for Solid JS apps",
5
5
  "license": "MIT",
@@ -44,7 +44,8 @@
44
44
  "typecheck": "tsc --noEmit"
45
45
  },
46
46
  "optionalDependencies": {
47
- "@tonejs/midi": "^2.0.28"
47
+ "@tonejs/midi": "^2.0.28",
48
+ "tone": "^14.7.77"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "solid-js": ">=1.0.0"